如何创建一个有条件定义类型的对象?

How do I create an object with its type defined conditionally?

我有一系列 类 每个都有不同的属性,每个都有一个 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 种类型。

最好的方法是定义一个包含 ID 属性 的 Attribute-Subclass,然后使用为每种类型提供唯一 ID 的属性来注释所有类型。
您可以收集和过滤包含给定属性的加载类型,并按属性的 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);
        }
    }
}

如果我理解你的问题,这里有一种解决方法(有很多)。

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

...有很多方法可以做到这一点,但这里有一个简单的方法...

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