反思 - 对象比较&默认值

时间:2013-03-14 14:49:36

标签: c# reflection object-comparison

我正在尝试比较C#中的两个复杂对象,并生成一个包含两者之间差异的字典。

如果我有这样的课程:

public class Product
{
    public int Id {get; set;}
    public bool IsWhatever {get; set;}
    public string Something {get; set;}
    public int SomeOtherId {get; set;}
}

一个例子,因此:

var p = new Product
                    {
                        Id = 1,
                        IsWhatever = false,
                        Something = "Pony",
                        SomeOtherId = 5
                    };

和另一个:

var newP = new Product
    {
        Id = 1,
        IsWhatever = true
    };

为了得到这些之间的差异,我正在做包括这个的东西:

var oldProps = p.GetType().GetProperties();
var newProps = newP.GetType().GetProperties();

// snip 
foreach(var newInfo in newProps)
{
    var oldVal = oldInfo.GetValue(oldVersion, null);
    var newVal = newInfo.GetValue(newVersion,null);
}

// snip - some ifs & thens & other stuff

这就是感兴趣的这条线

var newVal = newInfo.GetValue(newVersion,null);

使用上面的示例对象,此行将为SomeOtherId提供默认值0(bools& DateTimes& whathaveyou的相同故事)。

我正在寻找的方法是让newProps仅包含对象中明确指定的属性,因此在上面的示例中,IdIsWhatever。我玩过BindingFlags无济于事。

这可能吗?是否有更清洁/更好的方法来做到这一点,或者有一个工具来帮助我省去麻烦?

感谢。

3 个答案:

答案 0 :(得分:2)

如果您明确设置了某个属性,则没有标记。您可以做的是将属性声明为可空类型,并将值与null进行比较。

答案 1 :(得分:1)

如果我理解正确的话,这就是微软对xml包装类所做的,使用xsd实用程序生成,对于每个属性XIsSpecified,你有一个X或类似的东西。

所以这也是你可以做的 - 而不是public int ID{get;set;},添加一个私有成员_id,或者你选择调用它的任何东西,以及一个布尔属性IDSpecified每当调用Id的setter时都设置为true

答案 2 :(得分:0)

我最终修复了这个问题而没有使用反射(或者至少没有以这种方式使用它)。

或多或少,这样:

public class Comparable
{
    private IDictionary<string, object> _cache;

    public Comparable()
    {
        _cache = new Dictionary<string, object>();
    }

    public IDictionary<string, object> Cache { get { return _cache; } }

    protected void Add(string name, object val)
    {
        _cache.Add(name, val);
    }
}

产品实施到此:

public class Product : Comparable
{
    private int _id;
    private bool _isWhatever;
    private string _something;
    private int _someOtherId;

    public int Id {get { return _id; } set{ _id = value; Add("Id", value); } }
    public bool IsWhatever { get { return _isWhatever; } set{ _isWhatever = value; Add("IsWhatever ", value); } }
    public string Something {get { return _something; } set{ _something = value; Add("Something ", value); } }
    public int SomeOtherId {get { return _someOtherId; } set{ _someOtherId = value; Add("SomeOtherId", value); } }
}

然后比较非常简单

var dic = new Dictionary<string, object>();

foreach(var obj in version1.Cache)
{
    foreach(var newObj in version2.Cache)
    {
        //snip -- do stuff to check equality
        dic.Add(....);
    }
}

模型不会非常脏,而且效果很好。