Ответ 1
Вы можете просто использовать стандартный .NET DataBinder.Eval Method, например:
object result = DataBinder.Eval(myPerson, "PersonsAddress.HousePhone.Number");
Я пытаюсь получить доступ к различным частям вложенной структуры класса, используя строку произвольная.
Учитывая следующие (надуманные) классы:
public class Person
{
public Address PersonsAddress { get; set; }
}
public class Adddress
{
public PhoneNumber HousePhone { get; set; }
}
public class PhoneNumber
{
public string Number { get; set; }
}
Я хотел бы получить объект в "PersonsAddress.HousePhone.Number"
из экземпляра объекта Person
.
В настоящее время я занимаюсь рекурсивным поиском с использованием рефлексии, но я надеюсь, что у некоторых ниндзя есть несколько лучших идей.
Для справки, вот способ (дерьмовый), который я разработал:
private static object ObjectFromString(object basePoint, IEnumerable<string> pathToSearch)
{
var numberOfPaths = pathToSearch.Count();
if (numberOfPaths == 0)
return null;
var type = basePoint.GetType();
var properties = type.GetProperties();
var currentPath = pathToSearch.First();
var propertyInfo = properties.FirstOrDefault(prop => prop.Name == currentPath);
if (propertyInfo == null)
return null;
var property = propertyInfo.GetValue(basePoint, null);
if (numberOfPaths == 1)
return property;
return ObjectFromString(property, pathToSearch.Skip(1));
}
Вы можете просто использовать стандартный .NET DataBinder.Eval Method, например:
object result = DataBinder.Eval(myPerson, "PersonsAddress.HousePhone.Number");
В прошлом мне приходилось что-то подобное. Я пошел с лямбдой, потому что после их компиляции я могу их кэшировать. Я удалил кеширование в этом коде.
Я включил несколько модульных тестов, чтобы показать использование метода. Надеюсь, это будет полезно.
private static object GetValueForPropertyOrField( object objectThatContainsPropertyName, IEnumerable<string> properties )
{
foreach ( var property in properties )
{
Type typeOfCurrentObject = objectThatContainsPropertyName.GetType();
var parameterExpression = Expression.Parameter( typeOfCurrentObject, "obj" );
Expression memberExpression = Expression.PropertyOrField( parameterExpression, property );
var expression = Expression.Lambda( Expression.GetDelegateType( typeOfCurrentObject, memberExpression.Type ), memberExpression, parameterExpression ).Compile();
objectThatContainsPropertyName = expression.DynamicInvoke( objectThatContainsPropertyName );
}
return objectThatContainsPropertyName;
}
[TestMethod]
public void TestOneProperty()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Day" } );
Assert.AreEqual( dateTime.Day, result );
}
[TestMethod]
public void TestNestedProperties()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Date", "Day" } );
Assert.AreEqual( dateTime.Date.Day, result );
}
[TestMethod]
public void TestDifferentNestedProperties()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Date", "DayOfWeek" } );
Assert.AreEqual( dateTime.Date.DayOfWeek, result );
}
Здесь нерекурсивная версия с (почти) той же семантикой:
private static object ObjectFromString(object basePoint, IEnumerable<string> pathToSearch)
{
var value = basePoint;
foreach (var propertyName in pathToSearch)
{
var property = value.GetType().GetProperty(propertyName);
if (property == null) return null;
value = property.GetValue(value, null);
}
return value;
}
Поскольку вы уже заинтересованы в разрешении путей свойств строки, вам может пригодиться поиск в библиотеке запросов Dynamic LINQ, представленной в качестве примера Скоттом Гатри @Microsoft. Он анализирует ваши строковые выражения и создает экспресс-деревья, которые могут быть скомпилированы и кэшированы, как было предложено @Brian Dishaw.
Это предоставит вам множество дополнительных опций, предоставив простой и надежный синтаксис выражений, который вы можете использовать в своем конфигурационном подходе. Он поддерживает общие методы LINQ для перечислений, а также простую логику оператора, математические вычисления, оценку пути свойств и т.д.