IronLanguages / ironpython2

Implementation of the Python programming language for .NET Framework; built on top of the Dynamic Language Runtime (DLR).

Home Page:http://ironpython.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MongoDb GetCollection error: get MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

bnuzhouwei opened this issue · comments

.NET6 and IronPython 2.7.11

call the function:

def cnt():
    import System, clr
    clr.AddReference("MongoDB.Bson")
    clr.AddReference("MongoDB.Driver")
    from MongoDB.Bson import *
    from MongoDB.Driver import *
    connStr = "....."
    client = MongoClient(connStr)
    database = client.GetDatabase("db")    
    dataset = database.GetCollection[BsonDocument]("collection")
    return dataset.CountDocument(BsonDocument()) 
cnt()

database.GetCollection raise error:

System.InvalidOperationException: MongoDB.Driver.IMongoCollection`1[TDocument] GetCollection[TDocument](System.String, MongoDB.Driver.MongoCollectionSettings) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

The issue appears to be something like this:

public abstract class MyBaseClass {
    public abstract T GetCollection<T>();

    // this is just a helper to get an instance of the internal class
    public static MyBaseClass test() {
        return new MyInternalClass();
    }
}

internal sealed class MyInternalClass : MyBaseClass {
    public override T GetCollection<T>() {
        throw new NotImplementedException();
    }
}
MyBaseClass.test().GetCollection[object]

which results in:

SystemError: T GetCollection[T]() is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

A possible workaround is to enable private bindings with the PrivateBinding option.

Thanks, you are right, the code in mongodb driver is:

namespace MongoDB.Driver
{
	// Token: 0x020000C0 RID: 192
	internal sealed class MongoDatabaseImpl : MongoDatabaseBase
}

Internal without public....,

But how to to enable private bindings with the PrivateBinding option? Can add any paramters to the CreateEngine method?

IronPython.Hosting.Python.CreateEngine()

I modified the source code, changed the class MongoDatabaseImpl from internal to public, and recompile it.

namespace MongoDB.Driver
{
	public sealed class MongoDatabaseImpl : MongoDatabaseBase
}

The GetCollection in above code run correctly, but in mongodb, there are many methods with default value as default(CancellationToken), i.e.

long CountDocuments(FilterDefinition<TDocument> filter, CountOptions options = null, CancellationToken cancellationToken = default(CancellationToken));

but in IronPython, when we call the method:

GetCollection[BsonDocument]("collection")

got

IronPython.Runtime.Exceptions.TypeErrorException: expected CancellationToken, got NoneType

I seems that IronPython does't support default value for structs, such as default(CancellationToken)

But how to to enable private bindings with the PrivateBinding option? Can add any paramters to the CreateEngine method?

You can enable private binding like this:

Python.CreateEngine(new Dictionary<string, object> { {"PrivateBinding", true} });