子类中的唯一结构(C#)

子类中的唯一结构(C#),c#,inheritance,reflection,struct,C#,Inheritance,Reflection,Struct,我正在开发一个应用程序,从输入中生成二进制blob。由于二进制blob有很多类型,我想定义一个名为Config的父类,然后定义多个子类。父类将有一个生成二进制blob的方法,每个子类都有一个定义blob格式的唯一结构 家长: class Config { public struct BinaryFormat { public UInt16 _config_length; } // compile parameters to binary form

我正在开发一个应用程序,从输入中生成二进制blob。由于二进制blob有很多类型,我想定义一个名为Config的父类,然后定义多个子类。父类将有一个生成二进制blob的方法,每个子类都有一个定义blob格式的唯一结构

家长:

class Config
{
    public struct BinaryFormat
    {
        public UInt16 _config_length;
    }

    // compile parameters to binary format
    public byte[] CompileToBinary()
    {
        // find the binary format struct
        ??????

        foreach (var field in typeof(BinaryFormat).GetFields(BindingFlags.Instance | BindingFlags.Public))
        {
            string identifier = field.Name;
            if (identifier == "_config_length")
                continue;
            ConfigParameter param = FindParameterByIdentifier(identifier);
            if (param == null)
                throw new Exception("Struct field with no matching parameter (" + identifier + ")");
            field.SetValue(null, param.value);
        }

        int size = Marshal.SizeOf(cfg);
        cfg._config_length = (UInt16)size;
        byte[] buffer = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(cfg, ptr, true);
        Marshal.Copy(ptr, buffer, 0, size);
        Marshal.FreeHGlobal(ptr);

        return buffer;
    }
}
class Config
{
    public dynamic binary_struct;

    // compile parameters to binary format
    public byte[] CompileToBinary()
    {
        FieldInfo[] fieldinfo = Type.GetType(GetType().FullName + "+BinaryFormat").GetFields(BindingFlags.Instance | BindingFlags.Public);
        dynamic cfg = binary_struct;
        foreach (var field in fieldinfo)
        {
            string identifier = field.Name;
            if (identifier == "_config_length")
                continue;
            ConfigParameter param = FindParameterByIdentifier(identifier);
            if (param == null)
                throw new Exception("Struct field with no matching parameter (" + identifier + ")");
            field.SetValue(cfg, Convert.ChangeType(param.value, field.FieldType));
        }

        int size = Marshal.SizeOf(cfg);
        cfg._config_length = (UInt16)size;
        byte[] buffer = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(cfg, ptr, true);
        Marshal.Copy(ptr, buffer, 0, size);
        Marshal.FreeHGlobal(ptr);

        return buffer;
    }
}
儿童:

class ChildConfig : Config
{
    [StructLayout(LayoutKind.Sequential)]
    public struct BinaryFormat
    {
        public UInt16 _config_length;

        public sbyte config1;
        public sbyte config2;
        public sbyte config3;
    }
}
class ChildConfig : Config
{
    public cfgSettings()
    {
        binary_struct = new BinaryFormat();
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct BinaryFormat
    {
        public UInt16 _config_length;

        public sbyte Config1;
        public sbyte Config2;
        public sbyte Config3;
    }
}
CompileToBinary()
中,如果我刚刚创建了一个BinaryFormat类型的新变量,它将使用父类中的结构。如何使用子类中的结构

还是这完全是错误的做法


解决方案,基于m.rogalski的提示和代码

家长:

class Config
{
    public struct BinaryFormat
    {
        public UInt16 _config_length;
    }

    // compile parameters to binary format
    public byte[] CompileToBinary()
    {
        // find the binary format struct
        ??????

        foreach (var field in typeof(BinaryFormat).GetFields(BindingFlags.Instance | BindingFlags.Public))
        {
            string identifier = field.Name;
            if (identifier == "_config_length")
                continue;
            ConfigParameter param = FindParameterByIdentifier(identifier);
            if (param == null)
                throw new Exception("Struct field with no matching parameter (" + identifier + ")");
            field.SetValue(null, param.value);
        }

        int size = Marshal.SizeOf(cfg);
        cfg._config_length = (UInt16)size;
        byte[] buffer = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(cfg, ptr, true);
        Marshal.Copy(ptr, buffer, 0, size);
        Marshal.FreeHGlobal(ptr);

        return buffer;
    }
}
class Config
{
    public dynamic binary_struct;

    // compile parameters to binary format
    public byte[] CompileToBinary()
    {
        FieldInfo[] fieldinfo = Type.GetType(GetType().FullName + "+BinaryFormat").GetFields(BindingFlags.Instance | BindingFlags.Public);
        dynamic cfg = binary_struct;
        foreach (var field in fieldinfo)
        {
            string identifier = field.Name;
            if (identifier == "_config_length")
                continue;
            ConfigParameter param = FindParameterByIdentifier(identifier);
            if (param == null)
                throw new Exception("Struct field with no matching parameter (" + identifier + ")");
            field.SetValue(cfg, Convert.ChangeType(param.value, field.FieldType));
        }

        int size = Marshal.SizeOf(cfg);
        cfg._config_length = (UInt16)size;
        byte[] buffer = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(cfg, ptr, true);
        Marshal.Copy(ptr, buffer, 0, size);
        Marshal.FreeHGlobal(ptr);

        return buffer;
    }
}
儿童:

class ChildConfig : Config
{
    [StructLayout(LayoutKind.Sequential)]
    public struct BinaryFormat
    {
        public UInt16 _config_length;

        public sbyte config1;
        public sbyte config2;
        public sbyte config3;
    }
}
class ChildConfig : Config
{
    public cfgSettings()
    {
        binary_struct = new BinaryFormat();
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct BinaryFormat
    {
        public UInt16 _config_length;

        public sbyte Config1;
        public sbyte Config2;
        public sbyte Config3;
    }
}

使用虚拟/重写或抽象/重写方法

定义一个依赖于
BinayFormat
作为参数或使用受保护变量的方法。然后在子类中实现它。这样,只能从具有子类的
BinayFormat
类型的子类访问该功能


但这有一个缺点,您将无法访问父结构类型。您是否会使用父结构类型?如果您想互换使用它们,您可能希望它们都依赖于一个公共接口。

使用虚拟/重写或抽象/重写方法

定义一个依赖于
BinayFormat
作为参数或使用受保护变量的方法。然后在子类中实现它。这样,只能从具有子类的
BinayFormat
类型的子类访问该功能


但这有一个缺点,您将无法访问父结构类型。您是否会使用父结构类型?如果您想互换使用它们,您可能希望它们都依赖于一个公共接口。

因此,首先您的
ChildConfig
类将抛出关于隐藏成员某物的非常恼人的警告

class ChildConfig : Config
{
    [StructLayout(LayoutKind.Sequential)]
    public new struct BinaryFormat // now it wont
    {
        public UInt16 _config_length;

        public sbyte config1;
        public sbyte config2;
        public sbyte config3;
    }
}
第二件事是,在C#中,可以通过指定类型的“路径”来获取类型:

namespace.class.insideclass+inside_结构

但最好的是,大多数方法都被调用到“最顶层”对象,因此,例如,如果从
Config
调用
GetType()
,它将返回
Config
的class
Type
,但如果从
ChildConfig
调用,它将返回
ChildConfig
的class
Type
(才华横溢……)

知道你应该考虑重建你的逻辑有点:

// this was originaly
//foreach (var field in typeof(BinaryFormat).GetFields(BindingFlags.Instance | BindingFlags.Public))

// this should work with every BinaryFormat you want
foreach (var field in Type.GetType(GetType().FullName + "+BinaryFormat").GetFields(BindingFlags.Instance | BindingFlags.Public))
要创建实例,可以在基本
Config
对象中添加方法:

public object CreateInstance()
{
    return Activator.CreateInstance(Type.GetType(GetType().FullName + "+BinaryFormat"));
}
然后在派生类中使用它:

class ChildConfig : Config
{
    private BinaryFormat _format = (BinaryFormat)CreateInstance();
}

因此,首先,您的
ChildConfig
类将抛出关于隐藏成员内容的非常恼人的警告

class ChildConfig : Config
{
    [StructLayout(LayoutKind.Sequential)]
    public new struct BinaryFormat // now it wont
    {
        public UInt16 _config_length;

        public sbyte config1;
        public sbyte config2;
        public sbyte config3;
    }
}
第二件事是,在C#中,可以通过指定类型的“路径”来获取类型:

namespace.class.insideclass+inside_结构

但最好的是,大多数方法都被调用到“最顶层”对象,因此,例如,如果从
Config
调用
GetType()
,它将返回
Config
的class
Type
,但如果从
ChildConfig
调用,它将返回
ChildConfig
的class
Type
(才华横溢……)

知道你应该考虑重建你的逻辑有点:

// this was originaly
//foreach (var field in typeof(BinaryFormat).GetFields(BindingFlags.Instance | BindingFlags.Public))

// this should work with every BinaryFormat you want
foreach (var field in Type.GetType(GetType().FullName + "+BinaryFormat").GetFields(BindingFlags.Instance | BindingFlags.Public))
要创建实例,可以在基本
Config
对象中添加方法:

public object CreateInstance()
{
    return Activator.CreateInstance(Type.GetType(GetType().FullName + "+BinaryFormat"));
}
然后在派生类中使用它:

class ChildConfig : Config
{
    private BinaryFormat _format = (BinaryFormat)CreateInstance();
}

而不是
typeof(BinaryFormat)
尝试
Type.GetType(GetType.FullName+“.BinaryFormat”)
这将调用调用方对象的
GetType()
方法,并检索父对象中声明的
BinaryFormat
对象,而不是
typeof(BinaryFormat)
尝试
Type.GetType(GetType.FullName+“.BinaryFormat”)
这将调用调用方对象的
GetType()
方法,并检索父对象中声明的
BinaryFormat
对象。谢谢,这非常有帮助。不过,我仍然需要创建结构的实例,我很难做到这一点。我尝试了
dynamic cfg=(配置)Activator.CreateInstance(GetType().FullName,GetType().FullName+“.BinaryFormat”).Unwrap();
但是我得到了一个
无法加载文件或程序集'ConfigGen.ChildConfig'或其依赖项之一的异常。谢谢,这非常有用。不过我仍然需要创建该结构的实例,但我很难做到这一点。我尝试了
dynamic cfg=(Config)Activator.CreateInstance(GetType().FullName,GetType()).FullName+“.BinaryFormat”).Unwrap()
但是我得到了一个
无法加载文件或程序集'ConfigGen.ChildConfig'或其依赖项之一的异常。我正在考虑将父类中的方法设为静态,并只传递一个对子类的引用。然后,也许可以向子类添加一个可选方法,父类中的静态代码可以使用反射查找。似乎是一种迂回的方法。我正在考虑将父类中的方法设置为静态,并只传递一个对子类的引用。然后,可能会向子类添加一个可选方法,父类中的静态代码可以使用反射来查找。似乎是一种迂回的方法。