为什么我不能有一个类型的对象约束

时间:2012-11-28 23:18:34

标签: c# .net generics

我正在尝试设置自定义IDictionary,以允许Object作为我的TValue。

这是它的样子:

public class NullTolerantDictionary<TKey, TValue> 
             : Dictionary<TKey, TValue> where TValue : class
{
    public TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (TryGetValue(key, out value))
            {
                return value;
            }
            else
            {
                return DependencyProperty.UnsetValue;
            }
        }        
    }
}

当编译它时说:

  

无法将类型'object'隐式转换为'TValue'。

所以为了解决这个问题,我改变了我的类型约束:

where TValue : object

object代替班级)

然后我收到这条消息:

  

约束不能是特殊类'对象'

如何解决这个问题?

解释为什么object无法成为约束的额外信用。

2 个答案:

答案 0 :(得分:7)

这里的问题不是泛型类型参数约束,而是索引器的签名。

索引器被记录为始终返回TValue恰好是的任何内容。但是,else分支会尝试返回DependencyProperty.UnsetValue,其类型为object。由于并非所有object都是TValue s,编译器都会抱怨(“没有隐式转换”)。

如果您在TValue上放置了任意数量的约束,即使您可以将其约束为object,也没有区别。类型参数仍然可以设置为比object更多的派生,DependencyProperty.UnsetValue仍然无法转换为该类型。

如果您想达到这样的效果,可以使用public static只读属性,例如

public class NullTolerantDictionary<TKey, TValue> 
         : Dictionary<TKey, TValue> where TValue : class
{
    public static TValue MissingValue { get; private set; }
}

并从索引器返回,推测它可以用于参考比较。

但这仍然会留下一个问题:如何将TValue值实际用作MissingValue?您可以将new()约束放在TValue上并在静态构造函数中创建实例,但这会减少此类的可能应用程序。这导致设计开始变得有点笨拙使用,因为这正是你试图避免的那样,没有太大的意义。

答案 1 :(得分:5)

  

为什么对象不能成为约束?我该如何解决这个问题?

你没有。你不需要。 .NET中的所有托管类型都可以强制转换为object。有些东西不能(非托管指针等),但它们与泛型不兼容。

我猜,真正的问题是DependencyProperty.UnsetValueobject。嗯....这不是TValue。想象一下,TValueintbyteintbyte没有“未设置”值。您无法为此类object返回任意TValue

坦率地说,我只是让您的来电者直接使用TryGetValue,而不是使用此扩展方法。你可能做一些事情,比如返回一个带有TValue的虚拟类实例,或者返回null - 但坦率地说,调用者可以只调用TryGetValue 更方便地实现同样的目的。