简体   繁体   English

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

[英]Class properties of certain generic type cast into generic type to execute methods

First I would like to apologize for the messy title. 首先,我想为标题太乱表示歉意。 I'm not quite sure how to put it into words so I will describe the situation. 我不太确定如何把它写成文字,所以我将描述情况。

I'm writing a comparison engine for our product, that is capable of comparing different products like this: 我正在为我们的产品编写一个比较引擎,该引擎能够比较不同的产品,例如:

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

Actual products are derived from ComparableProduct, such as Screen : ComparableProduct, which adds property 实际产品派生自ComparableProduct,例如Screen:ComparableProduct,它增加了属性

ComparableProperty<decimal> Dimension { get; set; }

This means that I can have a class Laptop which has a property Keyboard, Screen, StorageDevice... etc etc, which are all derived from ComparableProduct. 这意味着我可以拥有一个类Laptop,该类具有属性Keyboard,Screen,StorageDevice ...等,这些属性均从ComparableProduct派生。

Those have in turn comparable properties like this: 依次具有类似的属性:

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

}

I haven't tested these, by all logic they should work. 我还没有测试过这些,从逻辑上讲它们都应该起作用。 The trouble I'm having... is with the IsBetterThan method in ComparableProduct. 我遇到的麻烦是与ComparableProduct中的IsBetterThan方法有关。 The expected functionality is that on the top class (say, Laptop), is looped through its ComparableProduct properties and called IsBetterThan for the other copy and those will loop through their subproperties... In addition, all the ComparableProduct ComparableProperty properties are checked with IsBetterThan with the other class' equivalent value. 预期的功能是,在顶级类(例如,笔记本电脑)上,通过其ComparableProduct属性进行循环,并为另一个副本调用IsBetterThan,而这些循环将通过其子属性进行循环...此外,所有的ComparableProduct ComparableProperty属性都通过IsBetterThan检查与其他类别的同等价值。

Anyway, here's what I have, and you can see the problem I have immediately. 无论如何,这就是我所拥有的,您可以立即看到我所遇到的问题。

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

As you can see, I'm trying to cast it to ComparableProperty<>, which means it's missing the generic type. 如您所见,我正在尝试将其强制转换为ComparableProperty <>,这意味着它缺少通用类型。 However, I'm not quite sure how to get the generic type of the involved property. 但是,我不太确定如何获取所涉及属性的泛型类型。

Also, if there's a better way of doing it... I will take any tips I can, but this is the first half decent way of doing it that came to my mind. 另外,如果有更好的方法可以做到……我会尽力提供一些技巧,但这是我想到的上半年不错的方法。

EDIT: 编辑:

Spoke too soon. 发言时间过早。 When I try to enumerate the properties in ComparableProduct's IsBetterThan like this: 当我尝试枚举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;
        }

Then it appears it can't find IComparableProperty in the interfaces. 然后似乎在接口中找不到IComparableProperty。 I have gone through the main methods that may contain it... but the only interfaces t contains are ICustomAttributeProvider, _MemberInfo, _PropertyInfo and ISerializable. 我已经遍历了可能包含它的主要方法...但是包含的唯一接口是ICustomAttributeProvider,_MemberInfo,_PropertyInfo和ISerializable。

EDIT 2: 编辑2:

I have solved this by falling back on string comparison on 我已经通过退回字符串比较解决了这个问题

if (property.PropertyType.Name != "ComparableProperty`1") continue;

And after changing T to ComparableProperty and IEnumerable to IEnumerable> the whole comparison works perfectly. 在将T更改为ComparableProperty并将IEnumerable更改为IEnumerable>之后,整个比较就可以完美地进行了。

You can create a non-generic interface, and then work with it: 您可以创建一个非通用接口,然后使用它:

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

EDIT 0: 编辑0:

Did you try to use this method Type.IsAssignableFrom(Type) like this: 您是否尝试过像下面这样使用此方法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);
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM