【问题标题】:Object reflection c#对象反射 c#
【发布时间】:2017-10-09 20:46:13
【问题描述】:

我想用一行代码而不是 switch case 生成正确的对象,因为总是在添加新设备时我必须添加新行。

是否可以在没有开关盒的情况下在一行中做到这一点?

public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
    // Create the Object with using reflection

    switch (TypeOfDevice)
    {
        case Device.enumDevice.A34411:
            return new A34411(string alias);
            break;
        case Device.enumDevice.N5744:
            return new N5744(string alias);
            break;
        default:
            throw new NotImplementedException();
    }

    return null;
}

【问题讨论】:

  • 您可以在类上放置自定义属性并使用反射,枚举Device 基类的所有子类,寻找具有正确值的属性。
  • 所以你的计划是也删除枚举的使用?
  • return new A34411(string alias); 这个语法不正确。删除string
  • 另外,最后的return null 是无用的,因为无法访问。所有可能的路径都以 switch 的一个分支结束,每个分支都返回或抛出异常。

标签: c#


【解决方案1】:

您可以将工厂方法作为委托存储在字典中

private static Dictionary<Device.enumDevice, Func<string, Device>> _factoryDict =
    new Dictionary<Device.enumDevice, Func<string, Device>>{
        [Device.enumDevice.A34411] = (alias) => new A34411(alias),
        [Device.enumDevice.N5744] = (alias) => new N5744(alias),
    };

...

public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
    if (_factoryDict.TryGetValue(TypeOfDevice, out var factory)) {
        return factory(alias);
    }
    throw new NotImplementedException();
    // No retun statement here, as it would be unreachable because of the throw statement.
}

或者,使用反射:

const string deviceNameSpace = "MyName.MyProject.Devices.";

public static Device GetDevice(Device.enumDevice deviceType, string alias)
{
    string typeName = deviceNameSpace + deviceType.ToString();
    Type type = Type.GetType(typeName, throwOnError: true);
    return (Device)Activator.CreateInstance(type, alias);
}

【讨论】:

  • 第二个例子不正确。 Type.GetType 在最简单的情况下需要“namespace.class”,但最好使用完整的 AssemblyQualifiedName。
  • @arndtdv:你是对的。如果类在同一个程序集中,则可以省略 AssemblyQualifiedName。
【解决方案2】:

一种优雅的方法是将依赖注入与“命名类型注册”一起使用

【讨论】:

    【解决方案3】:

    快速,但不是一个完整的例子:

    public abstract class Device
    {
        protected Device(string alias)
        {
            Alias = alias;
        }
        public string Alias { get; }
    }
    
    public class A1 : Device
    {
        public A1(string alias) : base(alias) { }
    }
    
    public class A2 : Device
    {
        public A2(string alias) : base(alias) { }
    }
    
    class DeviceAttribute : Attribute
    {
        public DeviceAttribute(Type type)
        {
            Type = type;
        }
    
        public Type Type { get; }
    }
    
    public enum DeviceEnum
    {
        [Device(typeof(A1))]
        A1,
        [Device(typeof(A2))]
        A2
    }
    
    public static class DeviceEnumExtension
    {
        public static Device GetInstance(this DeviceEnum obj, string alias)
        {
            var member = typeof(DeviceEnum).GetMember(obj.ToString());
    
            if (member[0].GetCustomAttributes(typeof(DeviceAttribute), false)[0] is DeviceAttribute deviceAttr)
            {
                var ctor = deviceAttr.Type.GetConstructor(new[] {typeof(string)});
                return ctor.Invoke(new object[] {alias}) as Device;
            }
            return null;
        }
    }
    
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            // Arrange
            var a1 = DeviceEnum.A1;
            var a2 = DeviceEnum.A2;
    
            // Act
            var instanceA1 = a1.GetInstance("A1");
            var instanceA2 = a2.GetInstance("A2");
    
            // Assert
            Assert.Equal(typeof(A1), instanceA1.GetType());
            Assert.Equal(typeof(A2), instanceA2.GetType());
            Assert.Equal("A1", instanceA1.Alias);
            Assert.Equal("A2", instanceA2.Alias);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      相关资源
      最近更新 更多