2016-09-29 4 views
3

У меня есть массив объектов значений ключа.Объект карты [] с свойствами свойства ключа к свойствам объекта без использования огромного неприятного переключателя

public class KeyValueStore 
{ 
    public string Key {get;set;} 
    public string Value {get;set;} 
} 

Этот массив содержит значение объекта я пытаюсь заполнить так:

public class Customer 
{ 
    public string Name {get;set;} 
    public string Country {get;set} 
} 

Так я хочу, чтобы отобразить эти ключи от KeyValueStore свойств клиентов

public Customer TransformToCustomer(KeyValueStore[] keyValueStore) 
{ 
    var customer = new Customer(); 

    foreach (var keyValue in keyValueStore) 
    { 
     switch (keyValue.Key) 
     { 
      case "Name": 
       customer.Name = keyValue.Value; 
       break; 
      case "Cntry": 
       customer.Country = keyValue.Value; 
       break; 
     } 
    } 

    return customer; 
} 

Is есть лучший способ сделать это?

+0

С быстрым взглядом будет сложно избежать любого типа кода переключения/поиска, поскольку ваши Ключи не являются событием, выстраивающимся под действие свойств. Я имею в виду '' Cntry '! = Country' –

+0

Предполагая, что ключи на самом деле являются именами свойств, без опечаток, посмотрите здесь: http://stackoverflow.com/questions/7718792/can-i-set-a-property -value-with-reflection – kiziu

+1

По какой-либо причине вы повторно изобретаете «Словарь» здесь с классом «KeyValueStore»? –

ответ

2

Да, при условии, что тип назначения имеет конструктор без параметров, вы могли бы написать общий метод, который делает это:

public T CreateAndPopulate<T>(IEnumerable<KeyValueStore> propStore, 
           IDictionary<string, string> mapping = null) 
          where T:class,new() 
{ 

    T item=new T(); 
    var type=typeof(T); 
    foreach(var kvs in propStore) 
    { 
     var propName = kvs.Key; 
     propName = mapping !=null && mapping.ContainsKey(propName) 
         ? mapping[propName] 
         : propName; 
     var prop = type.GetProperty(propName); 
     if(prop == null) //does the property exist? 
     { 
      continue; 
     } 
     var propMethodInfo = prop.GetSetMethod(); 
     if(propMethodInfo == null) //does it have a set method? 
     { 
      continue; 
     } 
     propMethodInfo.Invoke(item, new[]{ kvs.Value }); 
    } 
    return item; 
} 

и использовать его:

IEnumerable<KeyValueStore> propStore = new KeyValueStore[]{ 
    new KeyValueStore{ Key = "Name", Value = "John" }, 
    new KeyValueStore{ Key = "Cntry", Value = "UK" }}; 
var mapping = new Dictionary<string,string>{{ "Cntry", "Country" }}; 

var customer = CreateAndPopulate<Customer>(propStore, mapping); 
+0

Это сработало отлично! Большое спасибо. – PolkaHard

1

У меня есть другое предложение, много раз большие блоки блокировки указывают на то, что вы что-то упустили с помощью своих объектов desigen, и правильное использование полиморфизма может заменить использование коммутатора.

Сначала мы перепроектировать класс KeyValueStore для seprate классов ValueStore, что каждый из них будет реализовать общий интерфейс IValueStore, интерфейс будет выглядеть примерно так:

public interface IValueStore 
{ 
    void AddValueToCostumer(Customer customer); 
} 

Теперь NameValueStore будет выглядеть следующим образом:

public class NameValueStore : IValueStore 
{ 
    private readonly string _name;  

    public NameValueStore(string name) 
    { 
     _name = name; 
    } 

    public void AddValueToCustomer(Costumer costumer) 
    { 
     customer.Name = _name; 
    } 
} 

И CountryValueStore:

public class CountryValueStore : IValueStore 
{ 
    private readonly string _country;  

    public CountryNameValueStore(string country) 
    { 
     _country = country; 
    } 

    public void AddValueToCustomer(Costumer costumer) 
    { 
     customer.Country = _country; 
    } 
} 

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

public Customer TransformToCustomer(IValueStore[] valueStores) 
{ 
    var customer = new Customer(); 

    foreach (var valueStore in valueStores) 
    { 
     valueStore.AddValueToCustomer(customer); 
    } 

    return customer; 
} 

Это решение чувствует себя гораздо более SOLID мне.

Надеюсь, это поможет!

+0

Это не вариант для меня. мой класс Customer действительно очень большой. Я должен сделать 50 классов для всех свойств. Но это действительно может быть решением для небольших классов. Спасибо за помощь! :) – PolkaHard

+0

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

+0

И я тоже об этом согласен. :) Этот ответ был очень полезен для будущих проектов! – PolkaHard