C#泛型超类型通配符

C#泛型超类型通配符,c#,generics,wildcard,C#,Generics,Wildcard,我在C#中的泛型中遇到了通配符问题。运行我的小示例的第一种方法是使用对象作为泛型类型,因为它是所有事物的基类 public class AttributeManager { private Dictionary<int, AttributeItem<object>> attributes = new Dictionary<int, AttributeItem<object>>(); public v

我在C#中的泛型中遇到了通配符问题。运行我的小示例的第一种方法是使用对象作为泛型类型,因为它是所有事物的基类

   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;
    }
}
公共类属性管理器
{
私有字典属性=新字典();
公共void添加(AttributeItem属性)
{
if(hasAttribute(属性)){
返回;
}
Add(attribute.getKey(),attribute);
}
}
公共抽象类AttributeItem
{
私钥;
私人T属性值;
私有属性管理器属性管理器;
公共属性项(属性管理器属性管理器,int键)
{
this.key=key;
this.attributeManager=attributeManager;
attributeManager.add(this);//此行不起作用
}
公共无效设置值(T newValue)
{
attributeValue=新值;
}
公共T getValue()
{
返回属性值;
}
}
然而,该行:

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
        }

    }
公共类属性管理器
{
私人字典>();
/**
*如果hasAttribute(AttributeItem)返回false,此方法将添加新的AttributeItem。
*/
公共void添加(AttributeItem属性)
{
if(hasAttribute(属性)){
返回;
}
attributes.Add(attribute.getKey(),attribute);//此行失败
}
}
但正如您所看到的,我不知道我必须在声明中传递什么类型:

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

Dictionary您应该有如下内容:

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

}
公共类属性管理器
{
私有字典属性=新字典();
公共void添加(AttributeItem属性)
{
if(hasAttribute(属性)){
返回;
}
Add(attribute.getKey(),attribute);
}
}

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

private Dictionary<int, object> attributes = new Dictionary<int, object>();
private Dictionary attributes=new Dictionary();
这样,您的类仍然有一个很好的泛型接口,并且不需要泛型管理器实例

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

然而,该行:

attributeManager.add(此)

不起作用。它说没有为此调用找到重载方法。我认为>“this”将被强制转换为AttributeItem,因为对象必须是T的超类

你需要了解一下。基本上,仅仅因为
T
可转换为基类型并不意味着通用接口是可转换的。这完全取决于接口的用途

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


根据您需要对AttributeItem执行的操作,您可以定义一个逆变接口,其中只包含AttributeManager所需的通用返回值。

但是my AttributeManager也是通用的。但我希望它接受任何类型的属性。我忘了提这一点。啊,是的,我在设计解决方案时遇到了同样的问题,我个人最终重新设计了它。我想您是在试图避免出现在类声明AttributeManager上?是的。我不希望它是通用的太多。我希望它可以接受任何类型的属性。你可以使用一个接口来代替,并更改你的AttributeItem,使它具有where T:YourInterface约束?所以代码看起来像私有字典属性=new Dictionary();也许这有助于说明或思考如何使用通用属性字典,而不仅仅是“添加”。如前所述,由于您除了添加之外什么都不做,因此您也可以轻松地使用上面的DictionaryGree。我的解决方案可能会使事情变得过于复杂,但会给你这种通用的“感觉”。