在PHP
中,通常的做法是将数组作为类的选项传递,然后将该数组与另一个包含默认值的数组合并。
像这样。
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中提供的相同简单性的方式。
答案 0 :(得分: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);
}
}