C#通用超类型通配符

时间:2013-07-08 14:05:30

标签: c# generics wildcard

我在C#中使用泛型中的通配符时出现问题。让我的小例子运行的第一种方法是使用object作为泛型类型,因为它是所有东西的基类。

   public class AttributeManager
    {

        private Dictionary<int, AttributeItem<object>> attributes = new Dictionary<int, AttributeItem<object>>();

        public void add(AttributeItem<object> attribute)
        {
            if (hasAttribute(attribute)) {
                return;
            }
            attributes.Add(attribute.getKey(), attribute);
        }
    }

public abstract class AttributeItem<T>
{
    private int key;
    private T attributeValue;
    private AttributeManager attributeManager;

    public AttributeItem(AttributeManager attributeManager, int key)
    {
        this.key = key;
        this.attributeManager = attributeManager;
        attributeManager.add(this); // this line does not work
    }

    public void setValue(T newValue)
    {
        attributeValue = newValue;
    }

    public T getValue()
    {
        return attributeValue;
    }
}

但是,行:

  

attributeManager.add(本);

不起作用。它表示此调用没有找到重载方法。我认为“this”将被转换为AttributeItem,因为对象必须是T的超类。 所以我的第一个问题是为什么这个演员不起作用?

我的第二种方法是将AttributeManager更改为使用通配符:

   public class AttributeManager
    {

        private Dictionary<int, AttributeItem<????>> attributes = new Dictionary<int, AttributeItem<????>>();

        /**
         * This method will add a new AttributeItem if hasAttribute(AttributeItem) returns false.
         */
        public void add<T>(AttributeItem<T> attribute)
        {
            if (hasAttribute(attribute)) {
                return;
            }
            attributes.Add(attribute.getKey(), attribute); // this line fails
        }

    }

但正如你所看到的,我不知道我必须在声明中传递哪种类型:

Dictionary<int, AttributeItem<????>> attributes

所以我的第二个问题是,我必须使用什么而不是?????

此致 罗伯特

3 个答案:

答案 0 :(得分:2)

最简单的解决方案是在私人字典字段级别删除泛型:

private Dictionary<int, object> attributes = new Dictionary<int, object>();

这样你的类仍然有一个很好的通用接口,你不需要一个通用的Manager实例。

困难的部分是稍后从字典中获取有用的东西。您可以使用反射,但我建议您使用Onam和Robert Hahn建议的界面技术。如果这不能解决您的问题,请告诉我们有关您的用例的更多信息。

答案 1 :(得分:0)

你应该有这样的东西:

public class AttributeManager<T>
{

    private Dictionary<int, AttributeItem<T>> attributes = new Dictionary<int, AttributeItem<T>>();

    public void add(AttributeItem<T> attribute)
    {
        if (hasAttribute(attribute)) {
            return;
        }
        attributes.Add(attribute.getKey(), attribute);
    }

}

答案 2 :(得分:0)

  

但是,行:

     

attributeManager.add(本);

     

不起作用。它表示此调用没有找到重载方法。我以为&gt; “this”将被转换为AttributeItem,因为object必须是T

的超类

您需要了解covariance and contravariance。基本上,仅仅因为T可转换为基类型并不意味着通用接口。这一切都取决于接口用于什么

在您的情况下,T是一个输入参数,因此它不能是逆变的(启用AttributeItem转换)。否则,编译时合同将允许将对象传递给setValue,这不是有效的替换。

根据您使用AttributeItem 所需的内容,您可以使用AttributeManager的所需泛型返回值来定义逆变接口。