使用对象属性作为字典中的键
我想将对象属性用作字典的关键字。这可以做到吗?使用对象属性作为字典中的键
最终的目标是使用它,以便可以查看属性是否被锁定,在对象可以处于的各种状态下。这些锁定的值不会持久存在,只存在于模型的业务规则中。
查看字段是否锁定的理想代码将如下所示;
bool ageLocked = myObject.IsFieldLocked(x => x.Age);
bool nameLocked = myObject.IsFieldLocked(x => x.Name);
IsFieldLocked是myObject类型的扩展方法。
我希望字典能够在myObject中生存,并且可以根据对象的状态使用不同的字典变体进行替换,例如,已经下了命令或等待顺序会有不同的字典定义。
希望我能够使用工厂创建不同的字典变体;
Factory.CreateAwaitingOrderLockedFields()
Factory.CreateOrderPlacedLockedFields()
定义词典看起来像这样
new Dictionary< ***MissingMagic***, bool>()
{
{ x => x.Age , true},
{ x => x.Name, false}
}
目的是避免该密钥为字符串,强类型的关键是迄今为止较为理想。
我会将字典简单地定义为Dictionary<string, bool>
。
扩展方法则可能是这个样子:
public static bool IsFieldLocked<TField>(this MyClass self, Expression<Func<MyClass, TField>> propertyExpression)
{
// note: null checks etc omitted for brevity
var lambda = (LambdaExpression)propertyExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
string propertyName = memberExpression.Member.Name;
return self.InternalLockedFieldsDictionary[propertyName];
}
我认为你应该只使用继承。创建一个基类LockedField,然后创建继承此类的AwaitingOrderLockedField和OrderPlacedLockedField。
class LockedField {
}
class AwaitingOrderLockedField : LockedField {
}
class OrderPlacedLockedField : LockedField {
}
您的字典将IDictionary<LockedField, bool>
你可以声明与任何类型的关键字典;
Dictionary<Form,bool>
会创建一个字典,其中表单元素被用作关键字。
这是你在哪里问?
如果要使用几个不同的对象作为键,您可以使用Dictionary<object,bool>
或让所有对象从另一个对象Dictionary<masterobject,bool>
继承。
您将需要实现你想要的字典中键使用类IComparable接口:
public class MyObject : IComparable {
public int CompareTo(MyObject obj) {
// Comparison Logic
}
}
由于对于一个对象的成员来说,这不是一个真正的选项,您可能会很好地使用Dictionary<string, bool>
,并将字段名称作为键,并在您的IsFieldLocked()
方法中反射以从强类型字段中去除字符串。
这是我切下来的解决方案基于从咨询DER herzmeister welten
public class MyDtoOne : BaseFieldLockingDto<MyDtoOne>
{
public string Name { get; set; }
public int Age { get; set; }
public MyDtoOne()
{
LockedFields = new LockedFields<MyDtoOne>
{
{ x => x.Age, false },
{ x => x.Name, true }
};
}
}
public class MyDtoTwo : BaseFieldLockingDto<MyDtoTwo>
{
public DateTime DateOfBirth { get; set; }
public MyDtoTwo()
{
LockedFields = new LockedFields<MyDtoTwo>
{
{x => x.DateOfBirth, false}
};
}
}
public class BaseFieldLockingDto<TBaseObject>
{
public LockedFields<TBaseObject> LockedFields { get; set; }
public bool IsFieldLocked<TField>(Expression<Func<TBaseObject, TField>> propertyExpression)
{
return LockedFields.IsFieldLocked(propertyExpression);
}
}
public class LockedFields<TBaseObject> : Dictionary<string, bool>
{
public void Add<TField>(Expression<Func<TBaseObject, TField>> propertyExpression, bool isLocked)
{
Add(GenerateKey(propertyExpression), isLocked);
}
private static string GenerateKey<TField>(Expression<Func<TBaseObject, TField>> propertyExpression)
{
return GetLambdaPropertyName(propertyExpression);
}
public bool IsFieldLocked<TField>(Expression<Func<TBaseObject, TField>> propertyExpression)
{
if (Count == 0)
return false;
string propertyName = GetLambdaPropertyName(propertyExpression);
if (ContainsKey(propertyName) == false)
return false;
return this[propertyName];
}
private static string GetLambdaPropertyName<TField>(Expression<Func<TBaseObject, TField>> propertyExpression)
{
var lambda = (LambdaExpression) propertyExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression) lambda.Body;
memberExpression = (MemberExpression) unaryExpression.Operand;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.",
propertyExpression));
}
return memberExpression.Member.Name;
}
}
有了这个,我可以做以下;
private static void Main(string[] args)
{
var myDtoOne = new MyDtoOne();
bool ageLocked = myDtoOne.IsFieldLocked(x => x.Age);
bool nameLocked = myDtoOne.IsFieldLocked(x => x.Name);
Console.WriteLine(string.Format("Age locked is {0}", ageLocked ? "true" : "false"));
Console.WriteLine(string.Format("Name locked is {0}", nameLocked ? "true" : "false"));
myDtoOne.LockedFields = new LockedFields<MyDtoOne> {{x => x.Age, true}, {x => x.Name, false}};
bool ageLocked1 = myDtoOne.IsFieldLocked(x => x.Age);
bool nameLocked1 = myDtoOne.IsFieldLocked(x => x.Name);
Console.WriteLine(string.Format("Age locked is {0}", ageLocked1 ? "true" : "false"));
Console.WriteLine(string.Format("Name locked is {0}", nameLocked1 ? "true" : "false"));
var myDtoTwo = new MyDtoTwo();
bool dateOfBirth = myDtoTwo.IsFieldLocked(x => x.DateOfBirth);
Console.WriteLine(string.Format("Date of birth locked is {0}", dateOfBirth ? "true" : "false"));
myDtoTwo.LockedFields = new LockedFields<MyDtoTwo>() {{x => x.DateOfBirth, true}};
bool dateOfBirth1 = myDtoTwo.IsFieldLocked(x => x.DateOfBirth);
Console.WriteLine(string.Format("Date of birth locked is {0}", dateOfBirth1 ? "true" : "false"));
Console.ReadLine();
}
}
明智的内部存储类型字符串被封装,并获得了字典构造和字段锁定检查的强类型检查。非常感谢 – c00ke 2010-10-29 11:54:41
性能是否与此解决方案有关? – c00ke 2010-10-29 12:08:10
@ c00ke,不幸的是,实际上在创建表达式树时会有一些开销。但是你多久会调用这种方法?你必须测试它是否真的对你的方案产生影响。 – herzmeister 2010-10-29 12:35:28