创建 class 以比较自身实例的最佳方法
Best way to create a class for comparing instances of itself
我正在编写一个程序,该程序从数据库中获取数据并将其逐值与旧数据进行比较,然后需要能够:
- 输出旧数据
- 输出新数据
- 只输出差异
因此,为了简单起见,假设我创建了以下 class 来存储值:
class MyClass
{
// These fields will not be compared:
public string Id { get; set; }
public string Name { get; set; }
public string NONCompField1 { get; set; }
public int NONCompField2 { get; set; }
// These fields WILL be compared:
public string CompField1 { get; set; }
public int CompField2 { get; set; }
public int CompField3 { get; set; }
public double CompField4 { get; set; }
}
并且,正如我的示例中的名称所示,我想比较旧值和新值,但仅基于 CompFields
来找出差异。
我知道我可以硬编码解决方案如下:
public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
{
var RetVal = new List<Tuple<string, string, string>>();
if (CompField1 != Other.CompField1)
RetVal.Add(Tuple.Create("CompField1", CompField1, Other.CompField1));
if (CompField2 != Other.CompField2)
RetVal.Add(Tuple.Create("CompField2", CompField2.ToString(), Other.CompField2.ToString()));
if (CompField3 != Other.CompField3)
RetVal.Add(Tuple.Create("CompField3", CompField3.ToString(), Other.CompField3.ToString()));
if (CompField4 != Other.CompField4)
RetVal.Add(Tuple.Create("CompField4", CompField4.ToString(), Other.CompField4.ToString()));
return RetVal;
}
这给了我一个 Tuple<string, string, string>
of (Field_Name
, Current_Value
, Old_Value
) 并且效果很好,但我正在寻找更好的, 模式动态方式来做到这一点,这将允许在未来添加新字段 - 无论它们是 CompareFields
(需要更新 GetDiffs
)还是 NONCompFields
(不需要更新GetDiffs
).
我的第一个想法是使用 DataAnnotations
然后反射来查找具有特定属性的字段并循环遍历它们以获得 GetDiffs
方法,但这似乎是一种作弊/错误的方法做事
是否有更好/更成熟的方法可以最大限度地减少更新额外代码的需要?
谢谢!!!
创建一个委托列表,将项目投影到您要比较的每个不同属性,然后比较两个项目上每个投影的结果:
public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
{
var comparisons = new[]
{
Tuple.Create<string, Func<MyClass, object>>("CompField1", item => item.CompField1),
Tuple.Create<string, Func<MyClass, object>>("CompField2", item => item.CompField2),
Tuple.Create<string, Func<MyClass, object>>("CompField3", item => item.CompField3),
Tuple.Create<string, Func<MyClass, object>>("CompField4", item => item.CompField4),
};
return from comparison in comparisons
let myValue = comparison.Item2(this)
let otherValue = comparison.Item2(Other)
where !object.Equals(myValue, otherValue)
select Tuple.Create(comparison.Item1,
myValue.ToString(),
otherValue.ToString());
}
仅供参考 - 对于任何其他想要与我在这里所做的相同的人,我最终修改了我找到的代码 here。
这允许我做的是传入一个 属性 名称列表以用于比较(尽管该示例做相反的事情 - 它有一个要忽略的名称列表,但这是一个简单的更改) 否则修改非常简单。
希望这至少能帮助指导处于相同情况的其他人。
我正在编写一个程序,该程序从数据库中获取数据并将其逐值与旧数据进行比较,然后需要能够:
- 输出旧数据
- 输出新数据
- 只输出差异
因此,为了简单起见,假设我创建了以下 class 来存储值:
class MyClass
{
// These fields will not be compared:
public string Id { get; set; }
public string Name { get; set; }
public string NONCompField1 { get; set; }
public int NONCompField2 { get; set; }
// These fields WILL be compared:
public string CompField1 { get; set; }
public int CompField2 { get; set; }
public int CompField3 { get; set; }
public double CompField4 { get; set; }
}
并且,正如我的示例中的名称所示,我想比较旧值和新值,但仅基于 CompFields
来找出差异。
我知道我可以硬编码解决方案如下:
public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
{
var RetVal = new List<Tuple<string, string, string>>();
if (CompField1 != Other.CompField1)
RetVal.Add(Tuple.Create("CompField1", CompField1, Other.CompField1));
if (CompField2 != Other.CompField2)
RetVal.Add(Tuple.Create("CompField2", CompField2.ToString(), Other.CompField2.ToString()));
if (CompField3 != Other.CompField3)
RetVal.Add(Tuple.Create("CompField3", CompField3.ToString(), Other.CompField3.ToString()));
if (CompField4 != Other.CompField4)
RetVal.Add(Tuple.Create("CompField4", CompField4.ToString(), Other.CompField4.ToString()));
return RetVal;
}
这给了我一个 Tuple<string, string, string>
of (Field_Name
, Current_Value
, Old_Value
) 并且效果很好,但我正在寻找更好的, 模式动态方式来做到这一点,这将允许在未来添加新字段 - 无论它们是 CompareFields
(需要更新 GetDiffs
)还是 NONCompFields
(不需要更新GetDiffs
).
我的第一个想法是使用 DataAnnotations
然后反射来查找具有特定属性的字段并循环遍历它们以获得 GetDiffs
方法,但这似乎是一种作弊/错误的方法做事
是否有更好/更成熟的方法可以最大限度地减少更新额外代码的需要?
谢谢!!!
创建一个委托列表,将项目投影到您要比较的每个不同属性,然后比较两个项目上每个投影的结果:
public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
{
var comparisons = new[]
{
Tuple.Create<string, Func<MyClass, object>>("CompField1", item => item.CompField1),
Tuple.Create<string, Func<MyClass, object>>("CompField2", item => item.CompField2),
Tuple.Create<string, Func<MyClass, object>>("CompField3", item => item.CompField3),
Tuple.Create<string, Func<MyClass, object>>("CompField4", item => item.CompField4),
};
return from comparison in comparisons
let myValue = comparison.Item2(this)
let otherValue = comparison.Item2(Other)
where !object.Equals(myValue, otherValue)
select Tuple.Create(comparison.Item1,
myValue.ToString(),
otherValue.ToString());
}
仅供参考 - 对于任何其他想要与我在这里所做的相同的人,我最终修改了我找到的代码 here。
这允许我做的是传入一个 属性 名称列表以用于比较(尽管该示例做相反的事情 - 它有一个要忽略的名称列表,但这是一个简单的更改) 否则修改非常简单。
希望这至少能帮助指导处于相同情况的其他人。