Setelah beberapa percobaan, saya menemukan bahwa Anda dapat menulis konvensi diskriminator Anda sendiri. Saya tidak begitu mengerti mengapa, tetapi konvensi diskriminator default tampaknya menggunakan properti Name dari kelas tipe, alih-alih FullName, yang membuatnya tidak berguna untuk kelas generik.
Saya akhirnya menggunakan kode ini sebagai gantinya:
class FooDiscriminatorConvention : IDiscriminatorConvention
{
public string ElementName
{
get { return "_t"; }
}
public Type GetActualType(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType)
{
if(nominalType!=typeof(MyAbstractClass))
throw new Exception("Cannot use FooDiscriminator for type " + nominalType);
var ret = nominalType;
var bookmark = bsonReader.GetBookmark();
bsonReader.ReadStartDocument();
if (bsonReader.FindElement(ElementName))
{
var value = bsonReader.ReadString();
ret = Type.GetType(value);
if(ret==null)
throw new Exception("Could not find type " + value);
if(!ret.IsSubclassOf(typeof(MyAbstractClass)))
throw new Exception("Database type does not inherit from MyAbstractClass.");
}
bsonReader.ReturnToBookmark(bookmark);
return ret;
}
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
{
if (nominalType != typeof(MyAbstractClass))
throw new Exception("Cannot use FooDiscriminator for type " + nominalType);
return actualType.FullName;
}
}
Dan mendaftarkannya dengan
BsonSerializer.RegisterDiscriminatorConvention(typeof(MyGenericClass<>), new FooDiscriminatorConvention()); //is this needed?
BsonSerializer.RegisterDiscriminatorConvention(typeof(MyAbstractClass), new FooDiscriminatorConvention());
Saya juga harus membuat kelas dasar non-abstrak, untuk menghindari kesalahan "tidak dapat membuat instance kelas abstrak". Akan menyenangkan untuk memiliki kelas dasar abstrak, tetapi karena kelas turunan bersifat generik, saya tidak dapat menggunakan BsonKnownTypes.