2016-03-15 77 views
0

我試圖防止System.NullReferenceException。完全合格的屬性名稱

我有一個公司,其中有員工的集合。每個員工都有一系列技能。

SelectedEmployee指向Employee集合中當前選定的元素。

SelectedSkill指向技能集合中當前選定的元素。

我有一個ListView的ItemSource綁定到Skills集合; ListView的SelectedItem綁定到SelectedSkill。

當技能被刪除時我希望ListView滾動到最後一個元素。

private void DeleteSelectedSkillFromSelectedEmployee() 
{ 
    Company.SelectedEmployee.Skills.Remove(Company.SelectedEmployee.SelectedSkill); 
    EmployeeSkillsListView.ScrollIntoView(Company.SelectedEmployee.Skills.Last()); 
} 

如果沒有選擇員工,則SelectedEmployee將爲空。這將在方法內部執行任何操作時導致System.NullReferenceException。

注:我已經使用擴展方法來替換.Last(),因此它不會在空集合上出錯。

爲了解決這個問題我使用一個實用程序方法:

public static class Utils 
{ 
    public static bool PropertyExists(Object obj, String name) 
    { 
     foreach (String part in name.Split('.')) 
     { 
      if (obj == null) { return false; } 

      Type type = obj.GetType(); 
      System.Reflection.PropertyInfo info = type.GetProperty(part); 

      if (info == null) { return false; } 

      obj = info.GetValue(obj, null); 
     } 
     return obj != null; 
    } 
} 

所以它現在看起來是這樣的:上面

private void DeleteSelectedSkillFromSelectedEmployee() 
{ 
    if(Utils.PropertyExists(Company, "SelectedEmployee.SelectedSkill")) 
    { 
     Company.SelectedEmployee.Skills.Remove(Company.SelectedEmployee.SelectedSkill); 
     EmployeeSkillsListView.ScrollIntoView(Company.SelectedEmployee.Skills.Last()); 
    } 
} 

,一切工作正常。這不是確切的場景或代碼,所以不要擔心糾正以上任何內容(只是假設它工作正常)。這只是我真正感興趣的問題。

(想象一下,這是SelectedEmployee和SelectedSkill不爲null)

有沒有得到一個屬性的完全合格的名稱的方法嗎? 所以,我可以這樣做:

if(Utils.PropertyExists(Company, GetFullyQualifiedName(Company.SelectedEmployee.SelectedSkill))) 

凡GetFullyQualifiedName(Object)返回 「Company.SelectedEmployee.SelectedSkill」。

問題的第二部分:想象一下SelectedEmployee爲null:是否有任何方法允許將NullReference傳遞給方法? 我99.9%肯定答案是否定的:)

+3

你爲什麼用反射煩心事字符串?爲什麼不簡單檢查'Company.SelectedEmployee!= null'? – Jamiec

+0

想象一下,一個屬性有多少個零件;其中任何一個都可能爲空。 A.B.C.D.E.F.G.H.SelectedSkill。我不想有一個巨大的If語句來檢查每一個。 – James

回答

4

我不明白。爲什麼不乾脆:

private void DeleteSelectedSkillFromSelectedEmployee() 
{ 
    if(Company != null && 
    Company.SelectedEmployee != null && 
    Company.SelectedEmployee.Skills != null) 
    {   
    Company.SelectedEmployee.Skills.Remove(Company.SelectedEmployee.SelectedSkill); 
    EmployeeSkillsListView.ScrollIntoView(Company.SelectedEmployee.Skills.Last()); 
    } 
} 

或者在C#6

if(Company?.SelectedEmployee?.Skills != null) 
{ 
    ... 
} 

如果你仍然想有GetFullyQualifiedName方法,你可以使用可能是像最近的(不檢查錯誤,它只是一個快速的黑客):

public static string GetPathOfProperty<T>(Expression<Func<T>> property) 
{ 
    string resultingString = string.Empty; 
    var p = property.Body as MemberExpression; 
    while (p != null) 
    {    
    resultingString = p.Member.Name + (resultingString != string.Empty ? "." : "") + resultingString; 
    p = p.Expression as MemberExpression; 
    } 
    return resultingString;   
} 

然後使用它像:

GetPathOfProperty(() => Foo.Bar.Baz.SomeProperty); 

這將返回一個包含"Foo.Bar.Baz.SomeProperty"

Check it in a Fiddle

+1

也許還應該檢查'Company.SelectedEmployee.Skills'是否完整。 – Jamiec

+0

感謝您的回覆。我不知道?在if語句中使用。然而,正如我所提到的,代碼僅僅是一個例子,實際使用將會更多.selected.selected.selected.selected ..等我試圖找到一種沒有一個巨大的If語句的方式。能夠找到一個物業的完全合格的名稱將在幾個地方對我有用。有任何想法嗎? – James

+0

@詹姆斯沒有這樣的東西作爲一個屬性的「完全合格的名稱」。有一個類型的「組合限定名稱」(但包括文化,版本等),這可能不是你正在尋找的。在任何情況下,使用C#6中的空傳播操作數,你使用字符串的任何事情都會更容易出現重構錯誤,而且你基本上什麼也得不到(每個點一個「?」並不麻煩) – Jcl