Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
abrasat opened this issue Aug 29, 2023 · 0 comments

Comments

@abrasat
Copy link

abrasat commented Aug 29, 2023

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?

@abrasat abrasat changed the title ISubtypeFactory - how to use own constructor instead of default constructor? ISubtypeFactory - how to use custom constructor instead of default constructor? Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant