在我的Web应用程序中,我希望在通过UI更改某些内容时通知用户。例如,我的Project类看起来像这样
public class Project
{
public string Name { get; set; }
public TaskStatus Status { get; set; }
public string Planner { get; set; }
public DateTime ScheduleStart { get; set; }
public DateTime ScheduleEnd { get; set; }
public double EstimatedCost { get; set; }
public double ActualCost { get; set; }
public string AssignedTo { get; set; }
}
现在我在UI上显示此信息,并且具有更改某些内容(例如状态,日程安排,费用等)的特定用户可以更改此信息。所以我想要的是,当用户更改某些内容时,应该发送电子邮件通知项目经理让我们说或任何感兴趣的人。
我已经编写了所有其他必需的代码来发送电子邮件和管理权限等。现在我想具体查看确切改变的内容例如如果只更改了Planner或状态已更改,那么电子邮件应包含新旧值,如TFS生成通知
P.S:上面的代码显示了我的Project类的一个非常简单的版本,实际的类有30多个属性。所以我在想,不应该对每个单独的属性进行比较,而应该有一种更简单,更通用的方式告诉我哪些属性已经改变,以便我可以根据它们进行通知。
答案 0 :(得分:1)
基于反射的简单解决方案。请注意,它可以进行优化,并且它不支持(此时)比较内部集合/对象。比较对象必须是POD(普通旧数据)
public class Project
{
public string Name { get; set; }
public TaskStatus Status { get; set; }
public string Planner { get; set; }
public DateTime ScheduleStart { get; set; }
public DateTime ScheduleEnd { get; set; }
public double EstimatedCost { get; set; }
public double ActualCost { get; set; }
public string AssignedTo { get; set; }
public Project Clone()
{
// If your object has inner collections, or
// references to other objects, you'll have to deep
// clone them ***manually***!!!
return (Project)MemberwiseClone();
}
}
public static class SimpleComparer
{
// Item1: property name, Item2 current, Item3 original
public static List<Tuple<string, object, object>> Differences<T>(T current, T original)
{
var diffs = new List<Tuple<string, object, object>>();
MethodInfo areEqualMethod = typeof(SimpleComparer).GetMethod("AreEqual", BindingFlags.Static | BindingFlags.NonPublic);
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
object x = prop.GetValue(current);
object y = prop.GetValue(original);
bool areEqual = (bool)areEqualMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { x, y });
if (!areEqual)
{
diffs.Add(Tuple.Create(prop.Name, x, y));
}
}
return diffs;
}
private static bool AreEqual<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
}
现在,您需要Clone()
方法:
public class Project
{
public string Name { get; set; }
public TaskStatus Status { get; set; }
public string Planner { get; set; }
public DateTime ScheduleStart { get; set; }
public DateTime ScheduleEnd { get; set; }
public double EstimatedCost { get; set; }
public double ActualCost { get; set; }
public string AssignedTo { get; set; }
public Project Clone()
{
// If your object has inner collections, you'll have to deep
// clone them ***manually***!!!
return (Project)MemberwiseClone();
}
}
然后......
var current = new Project();
var original = current.Clone();
current.ActualCost = 10000;
var diffs = SimpleComparer.Differences(current, original);
foreach (var diff in diffs)
{
Console.WriteLine("'{0}' changed from {1} to {2}", diff.Item1, diff.Item3, diff.Item2);
}
答案 1 :(得分:0)
我假设您指的是财产价值而不是实际的类别&#39;属性。为了能够比较哪些属性值已更改,必须有两个版本的对象,比如old
和updated
。我建议实现IEquatable
接口,如果你有复杂的对象,在你的情况下是一个嵌套的类TaskStatus
,它也有你需要比较的属性。您还可以让TaskStatus
或其他嵌套类实现IEquatable
界面,这样您就不必担心比较它们的属性值,从而为您提供只需调用{{{ 1}}方法。您可以拥有在覆盖Project's Equals()
方法中获取更改的逻辑。
如果您不想对每个属性进行硬编码以进行比较,那么可以进行一些反思。 :)
Equals()
答案 2 :(得分:0)
您可以使用如下类,即使在UI上更新属性后,每次更改属性时都会存储属性的旧值和新值,然后该对象可用于检索这两个值。您需要做的就是在每个属性的set方法下创建此类的实例。您还可以在创建对象之前检查值是否已更改。
public class PropertyChangingEventArgs : EventArgs
{
public PropertyChangingEventArgs()
{
}
public PropertyChangingEventArgs(string propName, object oldValue, object newValue)
{
PropertyName = propName;
OldValue = oldValue;
NewValue = newValue;
}
public string PropertyName { get; set; }
public object OldValue { get; set; }
public object NewValue { get; set; }
}
在财产方面,你可以这样做:
private string family;
public string Family
{
get { return family; }
set
{
if (family != value)
{
PropertyChangingEventArgs e = new PropertyChangingEventArgs("Family", family, value);
OnPropertyChanging(e);
family = value;
OnPropertyChanged("Family");
}
}
}
更新后,您可以检查所有属性是否已更改(或者您可以在每次更改属性时继续填充已更改属性的列表)并使用旧值和新值邮寄列表。
答案 3 :(得分:-1)
看看PropertyChangedEventHandler
。如果我正确理解你的问题,我认为它应该成功。
https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1