2017-10-08 125 views
0

我想用一個代碼行生成正確的對象,而不是開關的情況下,因爲總是添加新設備時,我必須添加一個新行。對象反射c#

是否有可能在一行沒有開關的情況下做到這一點?

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; 
} 
+0

你在哪裏使用反射? – oerkelens

+1

您可以在類上使用自定義屬性並使用反射,枚舉'Device'基類的所有子類,然後使用正確的值查找該屬性。 –

+1

那麼你的計劃是去除enum的使用呢? –

回答

0

優雅的方法是使用依賴注入與「命名類型註冊記憶」

3

你可以在工廠方法爲代表存儲在一個字典

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); 
} 
+0

第二個示例不正確。 Type.GetType在最簡單的情況下需要「namespace.class」,但最好使用完整的AssemblyQualifiedName。 – arndtdv

+0

@arndtdv:你說得對。如果這些類在同一個程序集中,則可以省略AssemblyQualifiedName。 –

0

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

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); 
    } 
}