通过合并其他三个具有优先级来创建对象 (C# .NET 3.5)



我有三个C#(使用.NET 3.5作为旧版sw(的同一类(A,B,C(对象,具有所有公共属性(字符串,整数,短整型,字节,日期时间,双精度( 我需要通过合并"三个"对象来创建第四个 (D(。 如果 A 设置了一个属性(不是 null 或空(,我必须在 D 中设置它,否则我必须检查 B,然后作为最后一个 C。 最有效和最优雅的方法是什么? 我读过关于反思是正确的方法吗?

反射是一种方法。 下面是一个示例;可能不是最优雅的,但它可以建立在:

使用系统 使用系统反射;

命名空间测试 { 班级课程 { 静态空 主(字符串[] 参数( { 车 A = 新车 { 品牌 ="沃尔沃" };

Car B = new Car { Year = 2001, CreateDate = DateTime.Now }; Car C = new Car { ShortValue = 1, MSRP = 20000, ByteValue = 10 }; Car D = new Car(); Mapper mapobj = new Mapper(); D = mapobj.Map<Car>(A); D = mapobj.Compare<Car>(B, D); D = mapobj.Compare<Car>(C, D); // Car D now has all the initialized properties of A,B,C } public class Mapper { public T Map<T>(T data) { var _result = (T)Activator.CreateInstance(typeof(T), new object[] { }); foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()) { if (typeof(T).GetProperty(propertyInfo.Name) != null) typeof(T) .GetProperty(propertyInfo.Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public) .SetValue(_result, propertyInfo.GetValue(data)); } return _result; } public T Compare<T>(T data, T data2) { var _result = (T)Activator.CreateInstance(typeof(T), new object[] { }); foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()) { if (typeof(T).GetProperty(propertyInfo.Name) != null) { bool isnullvalue = false; DateTime zerodate = new DateTime(); switch (propertyInfo.PropertyType.Name) { case "String": if ((string)propertyInfo.GetValue(data) != null && (string)propertyInfo.GetValue(data2) == null) isnullvalue = true; break; case "Int32": if ((Int32)propertyInfo.GetValue(data) != 0 && (Int32)propertyInfo.GetValue(data2) == 0) isnullvalue = true; break; case "Int16": if ((Int16)propertyInfo.GetValue(data) != 0 && (Int16)propertyInfo.GetValue(data2) == 0) isnullvalue = true; break; case "Byte": if ((Byte)propertyInfo.GetValue(data) != 0 && (Byte)propertyInfo.GetValue(data2) == 0) isnullvalue = true; break; case "Double": if ((Double)propertyInfo.GetValue(data) != 0 && (Double)propertyInfo.GetValue(data2) == 0) isnullvalue = true; break; case "DateTime": // DateTime.Compare(date1, date2) DateTime time1 = (DateTime)propertyInfo.GetValue(data); DateTime time2 = (DateTime)propertyInfo.GetValue(data2); if (DateTime.Compare(time1, zerodate) != 0 && DateTime.Compare(time2, zerodate) == 0) isnullvalue = true; break; default: Console.WriteLine("No handler for type {} found"); Console.ReadLine(); Environment.Exit(-1); break; } if (isnullvalue) { typeof(T).GetProperty(propertyInfo.Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public) .SetValue(_result, propertyInfo.GetValue(data)); } else { typeof(T).GetProperty(propertyInfo.Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public) .SetValue(_result, propertyInfo.GetValue(data2)); } } } return _result; } } public class Car { public string Make { get; set; } public int Year { get; set; } public short ShortValue { get; set; } public byte ByteValue { get; set; } public DateTime CreateDate { get; set; } public double MSRP { get; set; } } }

}

毫无疑问,您可以在此处使基于反射的解决方案工作,但您可能不需要它。如果你知道要合并的类型,你可以编写一个非常简单的映射函数来处理这个问题。

例如,给定一个简单的类...

class MyClassToMap
{
public string MyString { get; set; }
public int MyInt { get; set; }
}

你可以写一个简单的方法...

MyClassToMap Map(params MyClassToMap[] toMap)
{
var mapped = new MyClassToMap();
foreach (var m in toMap)
{
// 'default' is shorthand for a type's uninitalized value. In the case of
// string, it resolves to "null", and in the case of int, it resolves to 0.
// You could also use the literal values here, if you prefer.
// Note that for C# versions < 7.1, you must specify the type--eg "default(string)".
// See: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/default
if (m.MyString != default) mapped.MyString = m.MyString;
if (m.MyInt != default) mapped.MyInt = m.MyInt;
}
return mapped;
}

并这样称呼它...

var a = new MyClassToMap { MyString = "foo", MyInt = 0 };
var b = new MyClassToMap { MyString = "bar", MyInt = 100 };
var c = new MyClassToMap { MyString = null, MyInt = 0 };
var mapped = Map(a, b, c);
Console.WriteLine($"MyString = {mapped.MyString}, MyInt = {mapped.MyInt}");
// prints: { MyString = "bar", MyInt = 100 };

您可以使用反射来实现此目的。例如,请检查以下代码(内联注释添加到解释该方法的方法中(

public T AssignProperties<T>(params T[] sources)
{
// Types of properties that has to be copied
var filteredPropertyTypes = new []{typeof(int),typeof(string),typeof(short),typeof(byte),typeof(DateTime),typeof(double)};
// Create Default Instance of T
var newInstance = (T)Activator.CreateInstance(typeof(T));
// Iterate through each property
foreach(var property in typeof(T).GetProperties().Where(x=>filteredPropertyTypes.Contains(x.PropertyType)))
{
// Get the default Value of the Type and get the first instance in sources, which has a non-default value for the property
var defaultValue = property.PropertyType.IsValueType ? Convert.ChangeType(Activator.CreateInstance(property.PropertyType),property.PropertyType) : null;
if(sources.Any(x=>!Convert.ChangeType(property.GetValue(x),property.PropertyType).Equals(defaultValue)))
{
var newValue = property.GetValue(sources.First(x=>!Convert.ChangeType(property.GetValue(x),property.PropertyType).Equals(defaultValue)));
property.SetValue(newInstance,newValue);
}
}
return newInstance;
}

现在,您可以将该方法用于 N 个实例 (A、B、C...(,并按需要处理的顺序传递实例。

var newInstance = AssignProperties(instanceA,instanceB,instanceC);

演示代码

最新更新