Skip to content

ISubtypeFactory - how to use custom constructor instead of default constructor? #226

@abrasat

Description

@abrasat

How can the BinarySerializer be configured, to use a SubtypeFactory instance which needs a constructor with parameters?
I have the following scenario in my application. In the first approach, only the deserialization would be required.

    public enum MyDataType: UInt32
    {
        Datatype_Invalid = 0,
        Datatype_Bool = 1,
        Datatype_Byte = 2,
        Datatype_Word = 3,
        Datatype_DWord = 4,
        Datatype_Float = 5,
        Datatype_Int16 = 6,
        Datatype_Int32 = 7,
        Datatype_String = 8,
        Datatype_Double = 9,
        Datatype_Spline = 10
    }

    public interface IItemSubtype
    {
    }

    public class ItemTypeByte : IItemSubtype
    {
        public byte Value { get; set; }
    }

    public class ItemTypeInt16 : IItemSubtype
    {
        public short Value { get; set; }
    }

    public class ItemTypeFloat : IItemSubtype
    {
        public float Value { get; set; }
    }

    public class ItemTypeDouble : IItemSubtype
    {
        public double Value { get; set; }
    }

    public class DefaultItemType : IItemSubtype
    {
        public byte[] Data { get; set; }
    }

    public class MyItemSubtypeFactory : ISubtypeFactory
    {
        private IDictionary<string, MyDataType> myDict;

       // how to inject this constructor ???
        public MyItemSubtypeFactory(IDictionary<string, MyDataType> dict)
        {
            myDict = dict;
        }

        public MyItemSubtypeFactory()
        {
        }

        // will not be used, only deserialization is necessary at this point (maybe later)
        public bool TryGetKey(Type valueType, out object key)
        {
            key = null;
            return false;
        }

        public bool TryGetType(object key, out Type type)
        {
            MyDataType keyVal = 0;
            bool keySuccess = myDict.TryGetValue((string)key, out keyVal);

            switch (keyVal)
            {
                case MyDataType.Datatype_Byte:
                    type = typeof(ItemTypeByte);
                    break;
                case MyDataType.Datatype_Int16:
                    type = typeof(ItemTypeInt16);
                    break;
                case MyDataType.Datatype_Float:
                    type = typeof(ItemTypeFloat);
                    break;
                case MyDataType.Datatype_Double:
                    type = typeof(ItemTypeDouble);
                    break;
                case MyDataType.Datatype_Spline:
                    // complex data-type, to be implemented later
                    type = null;
                    return false;
                default:
                    type = null;
                    return false;
            }
            return true;
        }
    }

    public class MyClassWithItemSubtypeFactory
    {
        [FieldOrder(0)]
        [FieldLength(4)]
        public string Key { get; set; }

        [FieldOrder(1)]
        [ItemSubtypeFactory(nameof(Key), typeof(MyItemSubtypeFactory))]
        [ItemSubtypeDefault(typeof(DefaultItemType))]
        public List<IItemSubtype> Items { get; set; }
    }

And the usage:

   // how to inject it into the SubtypeFactory constructor ?
    var dataTypeDictionary = new Dictionary<string, MyDataType>
    {
        { "abc", MyDataType.Datatype_Byte  },
        { "def", MyDataType.Datatype_Int16 },
        { "ghi", MyDataType.Datatype_Float }
    };
    var data = new byte[] { 97, 98, 99, 0, 17, 100, 101, 102, 0, 1, 12, 103, 104, 105, 0, 0x40, 0xb6, 0x66, 0x66 };
    var deserData = binSer.Deserialize<MyClassWithItemSubtypeFactory>(data);

The actual BinarySerializer implementation for TypeNode has only the option to choose the default constructor

var subtypeFactoryAttribute = attributes.OfType<SubtypeFactoryAttribute>().SingleOrDefault();
if (subtypeFactoryAttribute != null)
{
    SubtypeFactoryBinding = GetBinding(subtypeFactoryAttribute);
    SubtypeFactory =
         (ISubtypeFactory) subtypeFactoryAttribute.FactoryType.GetConstructor(Type.EmptyTypes)?.Invoke(null);
}

Maybe there is a possibility to call GetConstructors() to iterate the constructors and choose one of them according to some configuration. Or is it possible to inject somehow into the BinarySerializer an instance of the SubtypeFactory custom implementation?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions