2013-05-19 47 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); 
    } 
} 

你可以使用jQuery或引進merge功能其他圖書館在JavaScript中的東西。這些腳本可讓您獲取兩個Javascript對象並將它們合併在一起。允許您使用一個作爲默認值,另一個可以覆蓋這些默認值。

我發現這個模式非常有用,因爲它允許您配置一大組默認值,但只分配您需要的設置。

無論如何要在C#這樣做這樣的事情嗎?

我可以編寫一個函數,它使用反射在公共屬性上執行此操作,但我認爲這樣的事情一定已經完成了。

編輯:

這個問題已經被問過堆棧,但在提供相同的簡單性是什麼可以在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); 
    } 

}