Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
476 views
in Technique[技术] by (71.8m points)

c# - Fully-qualified property name

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 :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...