【问题标题】:Class properties of certain generic type cast into generic type to execute methods将某些泛型类型的类属性转换为泛型类型以执行方法
【发布时间】:2013-04-20 17:40:39
【问题描述】:

首先,我想为混乱的标题道歉。我不太清楚如何表达,所以我将描述这种情况。

我正在为我们的产品编写一个比较引擎,它能够像这样比较不同的产品:

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 并且这些将循环通过它们的子属性...此外,所有 ComparableProduct ComparableProperty 属性都使用 IsBetterThan 检查与其他类的等效值。

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

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,这意味着它缺少泛型类型。但是,我不太确定如何获得所涉及属性的泛型。

另外,如果有更好的方法...我会尽我所能,但这是我想到的前半个不错的方法。

编辑:

说得太早了。当我尝试像这样枚举 ComparableProduct 的 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 之后> 整个比较工作完美。

【问题讨论】:

    标签: c# .net generics reflection comparison


    【解决方案1】:

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

     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);
            }
    

    【讨论】:

    • 天哪,我似乎在不睡觉时失去了 50% 的智力。这确实是解决方案,谢谢!
    • 说得太早了。编辑 OP 以澄清。
    • 对,从技术上讲,答案仍然解决了我原来的问题,所以我会接受它。使用特定的界面可以解决问题,但如果我想使用强类型,我仍然需要弄清楚其中的一部分:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多