通过Reflection

时间:2018-02-19 13:37:36

标签: c# reflection

我正在实现Command设计模式的变体。我有一个带有一些子类的抽象CodedCommand类,每个子类都有一个类型为char的覆盖“Code”属性。然后,每个子类都有责任“封装”与其关联的自己的Code字母。

用例是:当某些串行解析器接收到char / byte时,我想创建相应子类的实例,以进一步处理命令有效负载。

我的问题是:我不知道如何从每个子类中获取特定值。

我目前的实施情况如下。用注释突出显示的问题是type.GetProperty("Code")返回null!

internal abstract class CodedCommand
{
    internal abstract char Code { get; }
}

internal class EventA : CodedCommand
{
    internal override char Code => 'A';
}

internal class EventB : CodedCommand
{
    internal override char Code => 'B';
}

public class CommandCreator
{
    Dictionary<char, Type> _typeMap 
        = new Dictionary<char, Type>();

    public CommandCreator()
    {
        var types = GetType().Assembly.GetTypes()
                                     .Where(type => type.IsSubclassOf(typeof(CodedCommand)))
                                     .Where(type => !type.IsAbstract);

        foreach (var type in types)
        {
            var field = type.GetProperty("Code");  // returns null!!!
            var value = field.GetValue(null);
            var code = (char)value;

            _typeMap[code] = type;
        }
    }


    CodedCommand BuildCommand(char code)
    {
        _typeMap.TryGetValue(code, out Type type);

        if (type != null)
        {
            return (CodedCommand)(Activator.CreateInstance(type));
        }

        return null;
    }
}

所以我的问题是如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

以下是获取财产价值的完整解决方案:

var types = GetType().Assembly.GetTypes()
   .Where(type => type.IsSubclassOf(typeof(CodedCommand)) && !type.IsAbstract);

foreach (var type in types)
{
    var obj = Activator.CreateInstance(type);
    var field = type.GetProperty("Code", BindingFlags.Instance | BindingFlags.NonPublic);
    var value = field.GetValue(obj);
    var code = (char)value;

    _typeMap[code] = type;
}

请注意field.GetValue需要对象实例才能工作,NonPublic - 获取内部属性的PropertyInformation时需要BindingFlag。

答案 1 :(得分:1)

问题是您的属性标记为internal,而不是public,我们无法使用您正在使用的重载访问非公共属性。

如果您想要flags以外的其他属性,则需要使用this overload指定public参数:

type.GetProperty("Code",BindingFlags.Instance | 
                        BindingFlags.NonPublic |
                        BindingFlags.Public)

GetProperty(String) overload

  

搜索具有指定名称的公共属性。

GetProperty(string name,BindingFlags bindingAttr) overload

  

使用指定的绑定约束搜索指定的属性。