Учитывая следующие объекты:
public class Customer {
public String Name { get; set; }
public String Address { get; set; }
}
public class Invoice {
public String ID { get; set; }
public DateTime Date { get; set; }
public Customer BillTo { get; set; }
}
Я хотел бы использовать отражение для прохождения через Invoice
добираться Name
свойство a Customer
. Вот то, что я после, предполагая, что этот код работал бы:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Конечно, это перестало работать начиная с "BillTo. Адрес" не является допустимым свойством Invoice
класс.
Так, я пытался писать метод, чтобы разделить строку на части на периоде и обойти объекты, ища окончательное значение, которым я интересовался. Это работает хорошо, но я не совсем доволен им:
public Object GetPropValue(String name, Object obj) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
Какие-либо идеи о том, как улучшить этот метод или лучший способ решить эту проблему?
РЕДАКТИРОВАНИЕ после регистрации, я видел несколько связанных сообщений... Кажется, нет ответа, который конкретно обращается к этому вопросу, как бы то ни было. Кроме того, я все еще хотел бы обратную связь на своей реализации.
Я на самом деле думаю, что ваша логика в порядке. Лично я бы, вероятно, изменил ее так, чтобы вы передали объект в качестве первого параметра (что более соответствует PropertyInfo.GetValue, так что менее удивительно).
Я бы также, вероятно, назвал ее более похожей на GetNestedPropertyValue, чтобы было очевидно, что она ищет в стеке свойств.
.Вы не объясняете источник вашего "дискомфорта", но ваш код, по сути, кажется мне звучным.
Единственное, что я бы поставил под сомнение - это обработка ошибок. Вы возвращаете ноль, если код пытается пройти через нулевую ссылку или если имя свойства не существует. Это скрывает ошибки: сложно узнать, вернул ли он ноль, потому что нет клиента BillTo, или вы неправильно написали "BilTo.Address"... или потому что есть клиент BillTo, и его адрес равен нулю! Я бы позволил этому методу упасть и сгореть в этих случаях - просто дайте исключению уйти (или, может быть, обернуть его в более дружелюбное).
.Вы должны получить доступ к АКТУАЛЬНОМУ объекту, на котором нужно использовать отражение. Вот что я имею в виду:
Вместо этого:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Сделайте это (отредактировано на основе комментария):
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo");
Customer cust = (Customer)info.GetValue(inv, null);
PropertyInfo info2 = cust.GetType().GetProperty("Address");
Object val = info2.GetValue(cust, null);
Посмотрите на этот пост для дополнительной информации: Использование отражения для установки свойства объекта
Попробуйте inv.GetType().GetProperty("BillTo+Address");
if (info == null) { /* throw exception instead*/ }
Я бы на самом деле сделал исключение, если бы они запросили несуществующее свойство. Как вы его закодировали, если я вызову GetPropValue и оно вернёт нуль, я не знаю, означает ли это, что свойства не существовало, или свойство действительно существовало, но его значение было нулевым
.