2017-02-15 3 views
2

Ich habe eine Reihe von Klassen mit jeweils unterschiedlichen Eigenschaften und jeder von ihnen mit einer ID (pro Typ nicht pro Instanz).Wie erstelle ich ein Objekt mit seinem definierten Typ bedingt?

Bei der folgenden:

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

Beim Lesen von Daten Ich habe nur ein ushort:

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

Wie verwende ich den Wert von EntityId verschiedene Arten von Objekten auf dem Wert basiert erstellen? Die Verwendung von if oder switch Anweisungen ist keine Option, da es mehr als 200 Typen geben wird.

+1

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

+0

@Matthew mit den Fabrik-Mustern , der Anrufer weiß, was er instanziiert werden soll. Wie Sie in dem C# -Codebeispiel sehen können, benötigt die Fabrik noch einen Schalter. – CodeCaster

+0

Das ist eine Möglichkeit, eine Fabrik zu machen. Es gibt viele andere. –

Antwort

3

Am besten wäre es, eine Attribut-Unterklasse zu definieren, die eine ID-Eigenschaft enthält, und dann alle Typen zu kommentieren, wobei das Attribut eine eindeutige ID für jeden Typ bereitstellt.
Layter Sie können geladene Typen, die bestimmte Attribute enthalten und filtern, nach der ID-Eigenschaft des Attributs sammeln und filtern.
Mit diesem Ansatz konnten Sie später weitere Subtypen hinzufügen, ohne den Code zu ändern.
Die Umsetzung aussehen könnte:

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

Mit 200+ Arten, ist dies wahrscheinlich, wie ich es tun würde. –

+0

@MichaelGunter kann man nie wissen mit wievielen typen man in der zukunft umgehen muss :) –

+2

Persönlich wenn ich schon über 200 typen deklariert hätte würde ich ein neues Muster finden. Das klingt nach einem Wartungs-Albtraum. –

8

Wenn ich verstehe Ihre Frage, hier ist ein Weg, um darüber zu gehen (es gibt viele).

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

Ich schrieb das genaue gleiche Ding ... verdammt deine schnellen Finger! +1 – TyCobb

+0

Langsamer Tag bei der Arbeit. :) –

+0

@MichaelGunter sehr netter Ansatz (+1) von mir! – Christos

3

... Tonnen von Möglichkeiten, dies zu tun, aber hier ist ein einfacher ...

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

Sie erhalten meine +1 für die Verwendung von Lambdas, um Reflexionen zu vermeiden. –

+0

Ich mag dieses Muster, weil es es auch einfach macht, den Konstruktoren Parameter zur Verfügung zu stellen, wo ich sonst nicht dazu in der Lage wäre ... wie 'T Create () wo T class, new() {...}' –

Verwandte Themen