2013-05-19 4 views
1

В PHP обычно принято передавать массив как параметры для класса, а затем объединить этот массив с набором другого массива, который содержит значения по умолчанию.Слияние двух объектов аналогично PHP array_merge

Нечто подобное.

class MyObject 
{ 
    private static $defaults = array('value'=>10); 
    private $settings; 

    public function Something(array $settings = array()) 
    { 
      $this->settings = array_merge(static::defaults,$settings); 
    } 
} 

Вы можете сделать что-то в JavaScript с помощью JQuery или других библиотек, которые знакомят функцию merge. Эти сценарии позволяют вам взять два объекта Javascript и объединить их. Разрешить использовать один из них по умолчанию, а другой - переопределять эти значения по умолчанию.

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

Есть ли способ сделать что-то подобное в C#?

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

EDIT:

Этот вопрос был задан ранее на стеке, но не ответил таким образом, что обеспечивает такую ​​же простоту, как то, что может быть сделано в PHP и JavaScript.

+1

Возможный дубликат: http://stackoverflow.com/questions/1358877/what-is-the-best-way-to-merge-two-objects-during-runtime-using-c?rq=1 – cgTag

+0

Люди не делают этого в C#, потому что C# - статически типизированный язык. строки не используются для представления свойств объекта. Для чего вам это нужно? –

+0

Я хочу, чтобы это был простой способ установки группы свойств на новый объект. – cgTag

ответ

0

Я не смог найти ответ, который сделал именно то, что я хотел. Поэтому я написал небольшой метод для этого. Это займет два объекта одновременно и объединить их поля/свойства, если значение null представляет собой непризнанное поле/свойство.

Вот пример использования. Создайте класс для хранения параметров для класса связи, пусть у класса связи есть значения по умолчанию, а затем инициализируйте связь с пользовательскими настройками.

Пример настроек класса.

public class ComSettings 
{ 
    public int? Port; 
    public string? Address; 
    public bool? KeepAlive; 
} 

Пример класса, который использует эти настройки в конструкторе.

public class ComLibrary 
{ 
    private static ComSettings _defaults = new ComSettings { Port = 80, Address = "localhost" }; 

    protected ComSettings settings; 

    public ComLibrary(ComSettings pSettings) 
    { 
     this.settings = ObjectMerge<ComSettings>(_defaults, pSettings); 
    } 
} 

Это позволит различные классы использовать ComSettings, но каждый из них может иметь различные значения по умолчанию. Единственное ограничение заключается в том, что поле/свойства должны поддерживать null присвоений.

Вот реализация ObjectMerge.

/// <summary> 
    /// Creates a new object that contains the properties of the two objects merged together. 
    /// </summary> 
    /// <typeparam name="T">The class type to merge.</typeparam> 
    /// <param name="pDefaults">Instance of the defaults object.</param> 
    /// <param name="pSettings">Instance of the settings object.</param> 
    /// <returns>A new instance of T with the merged results.</returns> 
    public static T ObjectMerge<T>(T pDefaults, T pSettings, bool pMergeFields = true, bool pMergeProperties = true) where T : class, new() 
    { 
     T target = new T(); 
     Type type = typeof(T); 
     List<MemberInfo> infos = new List<MemberInfo>(type.GetMembers()); 

     foreach (MemberInfo info in infos) 
     { 
      // Copy values from either defaults or settings 
      if (pMergeFields && info.MemberType == MemberTypes.Field) 
      { 
       FieldInfo field = (FieldInfo)info; 
       if (field.IsPublic) 
       { 
        object value = field.GetValue(pSettings); 
        value = (value == null) ? field.GetValue(pDefaults) : value; 
        field.SetValue(target, value); 
       } 
      } 

      // Copy values from either defaults or settings 
      if (pMergeProperties && info.MemberType == MemberTypes.Property) 
      { 
       PropertyInfo prop = (PropertyInfo)info; 
       if (prop.CanWrite && prop.CanRead) 
       { 
        object value = prop.GetValue(pSettings, null); 
        value = (value == null) ? prop.GetValue(pDefaults, null) : value; 
        prop.SetValue(target, value, null); 
       } 
      } 
     } 

     return target; 
    } 

И вот простой модульный тест.

/// <summary> 
///This is a test class for CoreUtilsTest and is intended 
///to contain all CoreUtilsTest Unit Tests 
///</summary> 
[TestClass()] 
public class CoreUtilsTest 
{ 
    /// <summary> 
    /// A class to perform testing on. 
    /// </summary> 
    public class MyClassA 
    { 
     public string Param1; 
     public string Param2; 
     public string Param3; 
    } 

    /// <summary> 
    /// A class to perform testing on. 
    /// </summary> 
    public class MyClassB 
    { 
     private string _param1; 

     public string Param1 
     { 
      get { return _param1; } 
      set { _param1 = value; } 
     } 
     private string _param2; 

     public string Param2 
     { 
      get { return _param2; } 
      set { _param2 = value; } 
     } 
     private string _param3; 

     public string Param3 
     { 
      get { return _param3; } 
      set { _param3 = value; } 
     } 
    } 

    /// <summary> 
    ///A test for SetProperties 
    ///</summary> 
    [TestMethod()] 
    public void Merging_Fields() 
    { 
     MyClassA defaults = new MyClassA { Param1 = "defaults" }; 
     MyClassA settings = new MyClassA { Param2 = "settings" }; 
     MyClassA results = CoreUtils.ObjectMerge<MyClassA>(defaults, settings); 

     Assert.AreEqual("defaults", results.Param1); 
     Assert.AreEqual("settings", results.Param2); 
     Assert.AreEqual(null, results.Param3); 
    } 

    [TestMethod()] 
    public void Merging_Properties() 
    { 
     MyClassB defaults = new MyClassB { Param1 = "defaults" }; 
     MyClassB settings = new MyClassB { Param2 = "settings" }; 
     MyClassB results = CoreUtils.ObjectMerge<MyClassB>(defaults, settings); 

     Assert.AreEqual("defaults", results.Param1); 
     Assert.AreEqual("settings", results.Param2); 
     Assert.AreEqual(null, results.Param3); 
    } 

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