Fully-qualified property name

笑着哭i 提交于 2019-11-28 12:14:53

问题


I'm trying to prevent System.NullReferenceException.

I have a Company, which has a collection of Employees. Each Employee has a collection of Skills.

SelectedEmployee points to the currently selected element within the Employee collection.

SelectedSkill points to the currently selected element within the collection of Skills.

I have a ListView that has its ItemSource bound to the Skills collection; The ListView's SelectedItem is bound to the SelectedSkill.

When a Skill is deleted I want the ListView to scroll to the last element.

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

If an Employee has not been selected, then SelectedEmployee will be null. This will cause a System.NullReferenceException when doing anything inside the method.

NOTE: I've used an extension method to replace .Last() so it doesn't error on an empty collection.

To get around this I use a Util method:

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

So it now looks like this:

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

Everything above works fine. It's not the exact scenario, or code, so don't worry about correcting anything above (just assume it works fine). It's just the question below I'm really interested in finding out.

(Imagine for this that SelectedEmployee and SelectedSkill are not null)

Is there any way of getting the fully qualified name of a property? So I could do something like:

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

Where GetFullyQualifiedName(Object) returns "Company.SelectedEmployee.SelectedSkill".

Second part of the question: Imagine that SelectedEmployee is null: Is there any way of allowing a NullReference to be passed to a method? I'm 99.9% sure the answer is no :)


回答1:


I don't get it. Why not just:

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());
  }
}

Or in C#6

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

If you still want to have that GetFullyQualifiedName method, the nearest you could use could be something like (doesn't check for errors and it's just a quick hack):

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

Then use it like:

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

This would return a string containing "Foo.Bar.Baz.SomeProperty"

Check it in a Fiddle



来源:https://stackoverflow.com/questions/36009209/fully-qualified-property-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!