如何创建一个有条件定义类型的对象?
我有一系列的类都有不同的属性,每个类都有一个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
创造价值基于其价值不同类型的对象?使用if
或switch
语句不是一个选项,因为将会有200多种类型。
最好的方法是定义一个包含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);
}
}
}
对于200多种类型,这可能是我如何做到的。 –
@MichaelGunter你永远无法知道你将来需要处理的类型:) –
个人而言,如果我已经声明了200多种类型,我会找到一种新的模式。这听起来像是一场维修噩梦。 –
如果我明白你的问题,这里是去了解的一种方式(有很多)。
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]();
}
}
为了避免反射,您可以使用lambdas获得我的+1。 –
我喜欢这种模式,因为它还可以很容易地向构造函数提供参数,否则我将无法这样做...例如'T创建
https://en.wikipedia.org/wiki/Factory_method_pattern –
@Matthew同工厂模式,调用者知道他们想要实例化的东西。正如您在C#代码示例中看到的那样,工厂仍然需要一个开关。 – CodeCaster
这是做工厂的一种方式。还有很多其他的。 –