2017-02-15 123 views
2

我有一系列的类都有不同的属性,每个类都有一个ID(每种类型不是每个实例)。如何创建一个有条件定义类型的对象?

考虑以下几点:

public class TestEntity : EntityBase { 
    public override ushort ID { get; } = 1; 
    public override void something() { do_something(); } 
} 
public class OtherEntity : EntityBase { 
    public override ushort ID { get; } = 2; 
    public override void something() { something_else(); } 
} 

读数据时我只有一个ushort

ushort EntityId = BitConverter.ToUInt16(data.GetRange(CURRENT_POSITION + TILE_ENTITY_ID_OFFSET, TILE_ENTITY_ID_LENGTH).ToArray().Reverse().ToArray(), 0); 

如何使用的EntityId创造价值基于其价值不同类型的对象?使用ifswitch语句不是一个选项,因为将会有200多种类型。

+1

https://en.wikipedia.org/wiki/Factory_method_pattern –

+0

@Matthew同工厂模式,调用者知道他们想要实例化的东西。正如您在C#代码示例中看到的那样,工厂仍然需要一个开关。 – CodeCaster

+0

这是做工厂的一种方式。还有很多其他的。 –

回答

3

最好的方法是定义一个包含ID属性的Attribute-Subclass,然后使用为每个类型提供唯一ID的属性来注释所有类型。
Layter可以通过属性的ID属性收集和过滤包含给定属性和过滤器的加载类型。
使用这种方法,您可以稍后添加其他子类型,而无需修改使用代码。
实现可能看起来像:

public sealed class MyCustomAttribute : Attribute 
{ 
    public ushort Id { get; set; } 

    public MyCustomAttribute(ushort id) 
    { 
     this.Id = id; 
    } 
} 

public class MyDemoConsumer 
{ 
    public void MyConsumingMethod(ushort requiredTypeId) 
    { 
     var requestedType = AppDomain 
      .CurrentDomain 
      .GetAssemblies() 
      .SelectMany(asm => asm.GetTypes()) 
      .Where(type => type.GetCustomAttributes(typeof(MyCustomAttribute), false).Any()) 
      .Select(type => new { Type = type, CustomId = type.GetCustomAttributes(typeof(MyCustomAttribute), false).Cast<MyCustomAttribute>().Single().Id }) 
      .Where(item => item.CustomId == requiredTypeId) 
      .Select(item => item.Type) 
      .SingleOrDefault(); 

     if (requestedType != null) 
     { 
      var result = Activator.CreateInstance(requestedType); 
     } 
    } 
} 
+1

对于200多种类型,这可能是我如何做到的。 –

+0

@MichaelGunter你永远无法知道你将来需要处理的类型:) –

+2

个人而言,如果我已经声明了200多种类型,我会找到一种新的模式。这听起来像是一场维修噩梦。 –

8

如果我明白你的问题,这里是去了解的一种方式(有很多)。

private static Dictionary<ushort, Type> TypeMap = new Dictionary<ushort, Type>() 
                { 
                 { 1, typeof(TestEntity) }, 
                 { 2, typeof(OtherEntity) } 
                }; 

private EntityBase CreateEntity(ushort id) 
{ 
    var type = TypeMap[id]; 
    return (EntityBase) Activator.CreateInstance(type); 
} 
+0

我写了完全相同的东西......该死的快速手指! +1 – TyCobb

+0

工作缓慢。 :) –

+0

@MichaelGunter非常好的方法(+1)从我这里! – Christos

3

...吨这样做的方法,但这里有一个简单的...

class Program 
{ 
    static void Main() 
    { 
     var simpleFactory = new SimpleFactory(); 
     var entity = simpleFactory.Create(1); 
     entity.Something(); 
    } 
} 

public abstract class EntityBase 
{ 
    public abstract ushort ID { get; } 
    public abstract void Something(); 
} 

public class TestEntity : EntityBase 
{ 
    public override ushort ID { get { return 1; } } 
    public override void something() { } 
} 
public class OtherEntity : EntityBase 
{ 
    public override ushort ID { get { return 2; } } 
    public override void something() { } 
} 

public class SimpleFactory 
{ 
    private Dictionary<ushort, Func<EntityBase>> config = new Dictionary<ushort, Func<EntityBase>> 
    { 
     { 1,()=>new TestEntity()}, 
     { 2,()=>new OtherEntity()}, 
    }; 

    public EntityBase Create(ushort entityId) 
    { 
     if (!config.ContainsKey(entityId)) 
      throw new InvalidOperationException(); 

     return config[entityId](); 
    } 
} 
+1

为了避免反射,您可以使用lambdas获得我的+1。 –

+0

我喜欢这种模式,因为它还可以很容易地向构造函数提供参数,否则我将无法这样做...例如'T创建()其中T class new(){...} –

相关问题