Trước hết, hãy khai báo thuộc tính của bạn và thêm thuộc tính vào lớp học của bạn.
enum MyEnum
{
Undefined,
Set,
Reset
}
class MyEnumAttribute : Attribute
{
public MyEnumAttribute(MyEnum value)
{
Value = value;
}
public MyEnum Value { get; private set; }
}
[MyEnum(MyEnum.Reset)]
class ResetClass
{
}
[MyEnum(MyEnum.Set)]
class SetClass
{
}
[MyEnum(MyEnum.Undefined)]
class UndefinedClass
{
}
Sau đó, bạn có thể sử dụng mã này để tạo từ điển với enums và các loại và tạo kiểu động.
//Populate a dictionary with Reflection
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new {t, Attribute = t.GetCustomAttribute(typeof (MyEnumAttribute))}).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value, e => e.t);
//Assume that you dynamically want an instance of ResetClass
var wanted = MyEnum.Reset;
var instance = Activator.CreateInstance(dictionary[wanted]);
//The biggest downside is that instance will be of type object.
//My solution in this case was making each of those classes implement
//an interface or derive from a base class, so that their signatures
//would remain the same, but their behaviors would differ.
Như bạn có thể nhận thấy, gọi Activator.CreateInstance
không hoạt động. Do đó, nếu bạn muốn cải thiện hiệu suất một chút, bạn có thể thay đổi từ điển thành Dictionary<MyEnum,Func<object>>
và thay vì thêm các loại làm giá trị bạn sẽ thêm hàm bao hàm hàm tạo của mỗi lớp và trả về dưới dạng đối tượng.
EDIT: Tôi đang thêm một lớp ConstructorFactory
, được điều chỉnh từ trang this.
static class ConstructorFactory
{
static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
var paramsInfo = ctor.GetParameters();
var param = Expression.Parameter(typeof(object[]), "args");
var argsExp = new Expression[paramsInfo.Length];
for (var i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
var paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var newExp = Expression.New(ctor, argsExp);
var lambda = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
var compiled = (ObjectActivator<T>)lambda.Compile();
return compiled;
}
public static Func<T> Create<T>(Type destType)
{
var ctor = destType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).First();
Func<ConstructorInfo, object> activatorMethod = GetActivator<Type>;
var method = typeof(ConstructorFactory).GetMethod(activatorMethod.Method.Name, BindingFlags.Static | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(destType);
dynamic activator = generic.Invoke(null, new object[] { ctor });
return() => activator();
}
delegate T ObjectActivator<out T>(params object[] args);
}
Bạn có thể sử dụng nó như một thay thế cho Activator.CreateInstance
, nó cung cấp hiệu suất cao hơn nếu kết quả được lưu trữ.
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new { t, Attribute = t.GetCustomAttribute(typeof(MyEnumAttribute)) }).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value,
e => ConstructorFactory.Create<object>(e.t));
var wanted = MyEnum.Reset;
var instance = dictionary[wanted]();
Bạn có thể minh họa sự cố với tình huống 2 lần 2 (chuyển đổi trong mỗi chuyển đổi với 2 giá trị enum) không? –
Tôi nghĩ ngay cả khi bạn sử dụng thuộc tính trên lớp con, bạn sẽ phải sử dụng công tắc trong công tắc trong công tắc. bạn sẽ phải sử dụng sự phản chiếu để lấy các giá trị thuộc tính cho tất cả các lớp con và nó sẽ chậm. – 24x7Programmer