【问题标题】:Fully-qualified property name完全限定的属性名称
【发布时间】:2016-06-30 18:29:34
【问题描述】:

我正在尝试防止 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(),因此它不会在空集合上出错。

为了解决这个问题,我使用了 Util 方法:

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 不为空)

有什么方法可以获取属性的完全限定名称? 所以我可以这样做:

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

GetFullyQualifiedName(Object) 返回“Company.SelectedEmployee.SelectedSkill”的位置。

问题的第二部分:想象 SelectedEmployee 为 null:有没有办法允许将 NullReference 传递给方法? 我有 99.9% 的把握答案是否定的 :)

【问题讨论】:

  • 你为什么要考虑反射?为什么不简单地检查Company.SelectedEmployee != null
  • 想象一个属性有 n 个部分;其中任何一个都可以为空。 A.B.C.D.E.F.G.H.SelectedSkill。我不想有一个巨大的 If 语句来检查每一个。

标签: c# nullreferenceexception


【解决方案1】:

我不明白。为什么不只是:

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

【讨论】:

  • 可能还应该检查 Company.SelectedEmployee.Skills 以确保完整性。
  • 感谢您的回复。我不知道 ?在 if 语句中使用。但是,正如我所提到的,代码只是一个示例,实际用途将是更多的 .selected.selected.selected.selected.. 等等。我试图找到一种不使用巨大 If 语句的方法。能够在多个地方找到属性的完全限定名称对我很有用。有什么想法吗?
  • @James 没有属性的“完全限定名称”之类的东西。有一个类型的“程序集限定名称”(但包括文化、版本等),这可能不是您所关注的。在任何情况下,使用 C# 6 中的 ?. 空传播操作数,您使用字符串所做的任何事情都将更容易出现重构错误,并且您将基本上一无所获(每个点一个 ? 并不麻烦)
  • 对于你的第二个问题,答案是“不”,不存在这样的东西,你可以使用和解析 linq 表达式来伪造它(如GetNameForProperty(() =&gt; Property.SubProperty.ChildProperty),但同样,不值得麻烦和运行时性能命中...在 C#6 中,您可以使用 nameof(property),但这仅返回属性/类型/字段的名称,而不是其完整的“路径”(如果您想这样称呼它)
  • 是的,我是这么认为的。谢谢。我已经研究了一段时间,并认为没有办法,但我想我会把它扔在那里,以防万一我可以做一些很酷的事情来抓住它。我肯定会使用?替换反射。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-29
  • 2019-10-09
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多