Closed inethui closed 2 years ago
What have you tried already?
This is what I've tried, I got error "A type can only participate in one inheritance hierarchy"
[Fact]
public void InheritClassAndInterface()
{
MetaType metaTypeA = RuntimeTypeModel.Default.Add(typeof(ClassA), true);
MetaType metaTypeB = RuntimeTypeModel.Default.Add(typeof(ClassB), true);
MetaType metaType1 = RuntimeTypeModel.Default.Add(typeof(Interface1), true);
metaTypeB.AddSubType(1, typeof(ClassA));
metaType1.AddSubType(1, typeof(ClassA));
RuntimeTypeModel.Default.CompileInPlace();
}
private class ClassA : ClassB, Interface1
{
}
private class ClassB
{
}
public interface Interface1
{
}
Yeah, it means that each type can have only one base type specified. You still can inherit both but you have to decide to use fields either of type ClassB
or of type Interface1
.
There is also another option: to enable WriteAsDynamicType
on interface-typed fields in the [SerializableMember]
attribute (while having only ClassA : ClassB
inheritance specified in the TypeModel
).
using AqlaSerializer;
using AqlaSerializer.Meta;
namespace ConsoleApp5
{
public class MyTest
{
public void Execute()
{
MetaType metaTypeA = RuntimeTypeModel.Default.Add(typeof(ClassA), true);
MetaType metaTypeB = RuntimeTypeModel.Default.Add(typeof(ClassB), true);
metaTypeB.AddSubType(1, typeof(ClassA));
RuntimeTypeModel.Default.CompileInPlace();
var c = new TestClass
{
ClassA = new ClassA { Value1 = 1, Value2 = 2, Value3 = 3 },
ClassB = new ClassB { Value2 = 22 },
Interface1 = new ClassA { Value1 = 1, Value2 = 2, Value3 = 3 },
};
var c2 = RuntimeTypeModel.Default.DeepClone(c);
}
[SerializableType]
class TestClass
{
[SerializableMember(1, DynamicType = true)]
public Interface1 Interface1 { get; set; }
[SerializableMember(2)]
public ClassB ClassB { get; set; }
[SerializableMember(3)]
public ClassA ClassA { get; set; }
}
[SerializableType]
private class ClassA : ClassB, Interface1
{
[SerializableMember(1)]
public int Value3 { get; set; }
[SerializableMember(2)]
public int Value1 { get; set; }
}
[SerializableType]
[SerializeDerivedType(1, typeof(ClassA))]
private class ClassB
{
[SerializableMember(2)]
public int Value2 { get; set; }
}
public interface Interface1
{
public int Value1 { get; set; }
}
}
}
Thanks a lot. This is a great solution. Can "DynamicType = true" be defined through method calls?
RuntimeTypeModel.Default.Add(typeof(TestClass), true)[nameof(TestClass.Interface1)].SetSettings(x => x.V.WriteAsDynamicType = true, 0);
For now it can only be set for a member.
This works great. What would be the downsides of this approach? Does it make sense to always mark a field as "DynamicType = true" if its type is an interface? We have more than 10k classes and interfaces. Manually configure each of them is not practical, so we always prefer to set things up programmatically.
Sorry, the previous post that I deleted contained wrong information.
If you need to serialize interfaces or System.Object
then yes, usually you have to mark them as dynamic type.
This feature writes full runtime type name into output stream. The name is written only once per type so there is no big size overhead even if you have multiple dynamic fields of a same type.
This is also not very safe if you receive your stream from an untrusted source. An attacker may create any of types registered in the model if you use precompiled TypeModel
or any available type with supported contract attribute or any available list type if it's executed on RuntimeTypeModel
.
Also the LateReference
feature doesn't work with DynamicType
.
To prevent creating non-registered types you can set RuntimeTypeModel.AutoAddMissingTypes
to false
.
More specifically this is called when a new type is encountered in an input stream:
Thank you so much! It has been very helpful.
With the latest release such interface is automatically marked as a dynamic type
I have something like this: public class ClassA : ClassB, Interface1
How to model this? Does Aqla support this case?