2014-02-02 3 views
2

У меня есть Dictionary<string, object>, который содержит имя свойства как string и его значение как объект. У меня также есть продление Bind метод, который, посредством отражения, устанавливает, что имя Собственость с соответствующим значением:Отражение для имен составных свойств

public static T Bind<T>(this T @this, 
         Dictionary<string, object> newValues, 
         params string[] exceptions) where T : class 
{ 
    var sourceType = @this.GetType(); 
    foreach (var pair in newValues.Where(v => !exceptions.Contains(v.Key))) 
    { 
     var property = sourceType.GetProperty(pair.Key, 
               BindingFlags.SetProperty | 
               BindingFlags.Public  | 
               BindingFlags.Instance); 
     var propType = Nullable.GetUnderlyingType(property.PropertyType) ?? 
         property.PropertyType; 
     property.SetValue(@this, (pair.Value == null) ? null : 
           Convert.ChangeType(pair.Value, propType), null); 
    } 
    return @this; 
} 

Например, рассмотрим класс, как это:

public class User 
{ 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
} 

Все работает отлично, за исключением того, когда Я получил класс с именем свойства другого объекта, например:

public class User 
{ 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
    public Address Address { get; set; } 
} 

public class Address 
{ 
    public string PostalCode { get; set; } 
} 

Так что, если я пытаюсь отправить имя на Name свойства, хорошо, бу t У меня возникли проблемы с именами составных свойств, например Address.PostalCode.

Можете ли вы посоветовать способ справиться с этой ситуацией?

EDIT # 1:

Резюмируя проблему: вызов sourceType.GetProperty("Name", ...) в контексте экземпляра класса User правильно позволяет установить его значение, но он не работает, используя sourceType.GetProperty("Address.PostalCode", ...) в одном экземпляре.

EDIT # 2: Более полный пример должен быть:

var user = new User{ Address = new Address() }; 
var values = new Dictionary<string, object> 
{ 
    { "Name"    , "Sample"  }, 
    { "Date"    , DateTime.Today }, 
    { "Address.PostalCode", "12345"  } // Here lies the problem 
} 
user.Bind(values); 
+0

В чем проблема? Что происходит и что вы хотите вместо этого? – fejesjoco

+0

Я просто добавил дополнительную информацию, @fejesjoco –

+0

Вы говорите, что, как будто это небольшая исправляемая ошибка в вашей программе, что путь множественного связывания не работает, но это совершенно новая функция, о которой вы просите. – fejesjoco

ответ

0

я был в состоянии решить ее идентификацией, если имя свойства имеет период и повторяющуюся его:

public static T Bind<T>(this T @this, 
       Dictionary<string, object> newValues, 
       params string[] exceptions) where T : class 
{ 
    var sourceType = @this.GetType(); 
    var binding = BindingFlags.Public | BindingFlags.Instance; 
    foreach (var pair in newValues.Where(v => !exceptions.Contains(v.Key))) 
    { 
     if(pair.Key.Contains(".")) 
     { 
      var property = sourceType.GetProperty(
          pair.Key.Split('.').First(), 
          binding | BindingFlags.GetProperty); 
      var value = property.GetValue(@this, null); 
      value.Bind(new Dictionary<string, object> 
      { 
       { 
        String.Join(".", pair.Key.Split('.').Skip(1).ToArray()), 
        pair.Value 
       } 
      }); 
     } 
     else 
     { 
      var property = sourceType.GetProperty(pair.Key, 
          binding | BindingFlags.SetProperty); 
      var propType = Nullable.GetUnderlyingType(property.PropertyType) ?? 
          property.PropertyType; 
      property.SetValue(@this, (pair.Value == null) ? null : 
        Convert.ChangeType(pair.Value, propType), null); 
     } 
    } 
    return @this; 
} 

Использование:

var user = new User {Address = new Address{ User = new User() }}; 
var values = new Dictionary<string, object>() 
{ 
    {"Name", "Sample"}, 
    {"Date", DateTime.Today}, 
    {"Address.PostalCode", "12345"}, 
    {"Address.User.Name", "Sub Sample"} 
}; 

user.Bind(values); 

public class User 
{ 
    public string Name  { get; set; } 
    public DateTime Date  { get; set; } 
    public Address Address { get; set; } 
} 

public class Address 
{ 
    public string PostalCode { get; set; } 
    public User User  { get; set; } 
} 
0

Я думаю, что Convert.ChangeType работает только для объектов реализации IConvertible. Таким образом, я просто добавлю чек и использую только Convert.ChangeType, если pair.Value имеет тип, который реализует IConvertible. Кроме того, AFAIK Преобразовать не использует перегруженные операторы преобразования, так что вы можете сохранить этот чек, когда pair.Value не структура, т.е.

object value; 
if (pair.Value == null) { 
    value = null; 
} else { 
    value = pair.Value.GetType().IsStruct ? Convert.ChangeType(pair.Value, propType) : pair.Value; 
} 
... 
0

Есть много вяжущих двигателей там, WPF, ASP.NET MVC, winforms в ядре .NET и кто знает, сколько других вы можете проверить все свои исходные коды и документацию об их синтаксисе.

Посмотрим самый простой случай. Предположим, что переменная X содержит объект, и у вас есть обязательное выражение «A.B.C». Давайте разделим путь привязки, первая часть - «A». Таким образом, вы используете отражение, чтобы получить свойство с именем «A» в X, и вы поместили этот другой объект в X. Теперь идет вторая часть «B», поэтому давайте найдем свойство «B» в (новом) X. Вы находите это и помещаете это в X. Теперь вы попадаете в финальную часть «C», и теперь вы можете читать или записывать это свойство в X. Дело в том, что вам не нужна рекурсия или что-то еще, это просто простой цикл, вы перебираете части выражения привязки, оцениваете их и сохраняете текущий объект в одной и той же переменной.

Но факт в том, что он может стать намного сложнее, чем это. Вы можете запросить индексацию массива, например «A.B [2] .C». Или что, если у вас есть путь «A.B», а X.A - нуль, что вы делаете? Создайте X.A, но что, если ему не хватает открытого конструктора без параметров?

Я хочу, чтобы вы видели, что это может быть очень сложная проблема. Вы должны указать синтаксис и правила, а затем реализовать это. Вы не указали в своем вопросе точный синтаксис и правила, которые вы хотите использовать. И если это будет больше, чем простой случай, о котором я упоминал выше, то решение может быть слишком продолжительным.

+0

Спасибо за ваш ответ, но я не думаю, что у этого есть очень сложный сценарий, по крайней мере, он мне не нужен. Я использую RadGrid (Telerik), который позволяет использовать синтаксис '<% # Bind (" ")%>', а затем вызывать метод ExtractValuesFromItem для получения словаря 'as return. Поскольку ASP.NET может решить проблему «Bind» («Address.PostalCode»), я просто хочу получить такую ​​же функциональность, чтобы обновлять мои пользовательские свойства объекта со значениями, собранными в пользовательском интерфейсе. –

Смежные вопросы