Po kilku eksperymentach odkryłem, że można napisać własne konwencje dyskryminacyjne. Naprawdę nie mogę zrozumieć, dlaczego, ale domyślna konwencja dyskryminatora wydaje się używać właściwości Name klasy typu zamiast FullName, co czyni ją bezużyteczną w przypadku klas ogólnych.
Zamiast tego użyłem tego kodu:
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;
}
}
I zarejestrowanie go w
BsonSerializer.RegisterDiscriminatorConvention(typeof(MyGenericClass<>), new FooDiscriminatorConvention()); //is this needed?
BsonSerializer.RegisterDiscriminatorConvention(typeof(MyAbstractClass), new FooDiscriminatorConvention());
Musiałem również uczynić klasę bazową nieabstrakcyjną, aby uniknąć błędu „nie można utworzyć instancji klas abstrakcyjnych”. Byłoby miło mieć abstrakcyjną klasę bazową, ale ponieważ klasa pochodna jest ogólna, nie mogę używać BsonKnownTypes.