2010-10-29 105 views
4

我想將對象屬性用作字典的關鍵字。這可以做到嗎?使用對象屬性作爲字典中的鍵

最終的目標是使用它,以便可以查看屬性是否被鎖定,在對象可以處於的各種狀態下。這些鎖定的值不會持久存在,只存在於模型的業務規則中。

查看字段是否鎖定的理想代碼將如下所示;

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

目的是避免該密鑰爲字符串,強類型的關鍵是迄今爲止較爲理想。

回答

4

我會將字典簡單地定義爲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]; 
} 
+0

明智的內部存儲類型字符串被封裝,並獲得了字典構造和字段鎖定檢查的強類型檢查。非常感謝 – c00ke 2010-10-29 11:54:41

+0

性能是否與此解決方案有關? – c00ke 2010-10-29 12:08:10

+0

@ c00ke,不幸的是,實際上在創建表達式樹時會有一些開銷。但是你多久會調用這種方法?你必須測試它是否真的對你的方案產生影響。 – herzmeister 2010-10-29 12:35:28

0

我認爲你應該只使用繼承。創建一個基類LockedField,然後創建繼承此類的AwaitingOrderLockedField和OrderPlacedLockedField。

class LockedField { 
} 

class AwaitingOrderLockedField : LockedField { 
} 

class OrderPlacedLockedField : LockedField { 
} 

您的字典將IDictionary<LockedField, bool>

0

你可以聲明與任何類型的關鍵字典;

Dictionary<Form,bool> 

會創建一個字典,其中表單元素被用作關鍵字。

這是你在哪裏問?

如果要使用幾個不同的對象作爲鍵,您可以使用Dictionary<object,bool>或讓所有對象從另一個對象Dictionary<masterobject,bool>繼承。

0

您將需要實現你想要的字典中鍵使用類IComparable接口:

public class MyObject : IComparable { 
    public int CompareTo(MyObject obj) { 
    // Comparison Logic 
    } 
} 

由於對於一個對象的成員來說,這不是一個真正的選項,您可能會很好地使用Dictionary<string, bool>,並將字段名稱作爲鍵,並在您的IsFieldLocked()方法中反射以從強類型字段中去除字符串。

1

這是我切下來的解決方案基於從諮詢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(); 
    } 
} 
相關問題