某些泛型类型的类属性转换为泛型类型以执行方法

时间:2013-04-20 17:40:40

标签: c# .net generics reflection comparison

首先,我想为凌乱的头衔道歉。我不太确定如何将其写入文字,所以我将描述情况。

我正在为我们的产品编写比较引擎,能够比较不同的产品:

public abstract class ComparableProduct
{
    public ComparableProperty<decimal> Weight { get; set; }
    public ComparableProperty<decimal> Width { get; set; }
    public ComparableProperty<decimal> Height { get; set; }
    public ComparableProperty<decimal> Depth { get; set; }
    public bool IsBetterThan(ComparableProduct target){}
}

实际产品派生自ComparableProduct,例如Screen:ComparableProduct,它增加了属性

ComparableProperty<decimal> Dimension { get; set; }

这意味着我可以拥有一台具有属性Keyboard,Screen,StorageDevice等等的笔记本电脑,它们都来自ComparableProduct。

那些具有可比较的属性如下:

public abstract class ComparableProperty<T> where T : IComparable<T>
{
    T Value { get; set; }
    public ComparisonType ComparisonType { get; set; }
    public bool IsBetterThan(T target)
    {
        if(ComparisonType == ComparisonType.GreaterThan)
            return Value.CompareTo(target) >= 0;
        return Value.CompareTo(target) <= 0;
    }

    public bool IsBetterThan(IEnumerable<T> targets)
    {
        foreach(var target in targets)
        {
            if (ComparisonType == ComparisonType.SmallerThan && Value.CompareTo(target) >= 0)
                return false;
            if (ComparisonType == ComparisonType.GreaterThan && Value.CompareTo(target) <= 0)
                return false;
        }
        return true;
    }

}

我还没有通过他们应该工作的所有逻辑对这些进行测试。我遇到的麻烦是使用ComparableProduct中的IsBetterThan方法。预期的功能是在顶级类(例如,笔记本电脑)上,通过其ComparableProduct属性循环,并为另一个副本调用IsBetterThan,这些将循环遍历其子属性...此外,使用IsBetterThan检查所有ComparableProduct ComparableProperty属性与其他班级#39;等价值。

无论如何,这里有我所拥有的,你可以立即看到我遇到的问题。

public bool IsBetterThan(ComparableProduct target)
    {
        foreach(var property in GetType().GetProperties().Where(x => x.PropertyType == typeof(ComparableProduct)))
        {
            var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as ComparableProduct;
            var local = property.GetValue(this, null) as ComparableProduct;
            if(local != null && !local.IsBetterThan(compareTo))
                return false;
        }
        foreach(var property in GetType().GetProperties().Where(x => x.PropertyType == typeof(ComparableProperty<>)))
        {
            var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as ComparableProperty<>;
            var local = property.GetValue(this, null) as ComparableProperty<>;
            if(local != null && !local.IsBetterThan(compareTo))
                return false;
        }
    }

正如您所看到的,我尝试将其投射到ComparableProperty&lt;&gt;,这意味着它缺少通用类型。但是,我不太确定如何获得所涉及的属性的泛型类型。

另外,如果有更好的方式做到这一点......我会采取任何我能做的提示,但这是我想到的上半部分做法。

修改

说得太快了。当我尝试枚举ComparableProduct&#39; IsBetterThan中的属性时:

foreach(var property in GetType().GetProperties())
        {
            var t = property.GetType().GetInterfaces();
            if (!property.GetType().GetInterfaces().Contains(typeof(IComparableProperty))) continue;

            var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as IComparableProperty;
            var local = property.GetValue(this, null) as IComparableProperty;
            if (local == null) continue;
            if(!local.IsBetterThan(compareTo))
                return false;
        }

然后它似乎无法在接口中找到IComparableProperty。我已经浏览了可能包含它的主要方法......但是包含的唯一接口是ICustomAttributeProvider,_MemberInfo,_PropertyInfo和ISerializable。

编辑2:

我已经通过回退

上的字符串比较来解决这个问题
if (property.PropertyType.Name != "ComparableProperty`1") continue;

将T改为ComparableProperty并将IEnumerable改为IEnumerable&gt;整个比较完美。

1 个答案:

答案 0 :(得分:0)

您可以创建非通用接口,然后使用它:

 public interface IComparableProperty
    {
        bool IsBetterThan(object target);

        bool IsBetterThan(IEnumerable targets);
    }

    public abstract class ComparableProperty<T>: IComparableProperty where T : IComparable<T>
    {
        T Value { get; set; }
        public ComparisonType ComparisonType { get; set; }
        public bool IsBetterThan(T target)
        {
            if (ComparisonType == ComparisonType.GreaterThan)
                return Value.CompareTo(target) >= 0;
            return Value.CompareTo(target) <= 0;
        }

        public bool IsBetterThan(IEnumerable<T> targets)
        {
            foreach (var target in targets)
            {
                if (ComparisonType == ComparisonType.SmallerThan && Value.CompareTo(target) >= 0)
                    return false;
                if (ComparisonType == ComparisonType.GreaterThan && Value.CompareTo(target) <= 0)
                    return false;
            }
            return true;
        }

        bool IComparableProperty.IsBetterThan(object target)
        {
            return IsBetterThan((T) target);
        }

        bool IComparableProperty.IsBetterThan(IEnumerable targets)
        {
            return IsBetterThan((IEnumerable<T>) (targets));
        }
    }

编辑0:

您是否尝试使用此方法 Type.IsAssignableFrom(Type),如下所示:

foreach (var property in GetType().GetProperties())
        {
            if (!typeof(IComparableProperty).IsAssignableFrom(property.PropertyType)) continue;

            var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as IComparableProperty;
            var local = property.GetValue(this, null) as IComparableProperty;
            if (local == null) continue;
            return local.IsBetterThan(compareTo);
        }