2017-02-15 4 views
2

У меня есть серия классов, каждая из которых имеет разные свойства, и каждый из них имеет идентификатор (для каждого типа не для экземпляра).Как создать объект с определенным типом?

Учитывая следующее:

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 для создания различных типов объектов на основе его стоимости? Использование операторов if или switch не является вариантом, так как будет более 200 типов.

+1

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

+0

@Matthew с рисунком фабрики , вызывающий абонент знает, что они хотят создать. Как вы можете видеть в примере кода C#, фабрике по-прежнему нужен коммутатор. – CodeCaster

+0

Это один из способов сделать завод. Есть много других. –

ответ

3

Лучшим способом было бы определить подкласс-подкласс, содержащий свойство 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

Вы получаете мой +1 за использование лямбда, чтобы избежать отражения. –

+0

Мне нравится этот шаблон, потому что он также упрощает предоставление параметров конструкторам, в которых я иначе не мог бы этого сделать ... например, T Создать () где T class, new() {...} ' –

Смежные вопросы