你能用隐式转换满足泛型约束吗?

def*_*mer 6 c# generics implicit-conversion

鉴于以下类型:

class A { }
class B
{
    public static implicit operator A(B me)
    {
        return new A();
    }
}

class Test<T> where T : A { }
Run Code Online (Sandbox Code Playgroud)

我试过了

var b = new Test<B>();
Run Code Online (Sandbox Code Playgroud)

并期望它失败,它做到了.但错误信息是

类型'B'不能用作泛型类型或方法'Test'中的类型参数'T'.没有从'B'到'A'的隐式引用转换.

但是,从B到A的隐式引用转换是这只是一个奇怪的消息?没有隐式引用转换为亚当·罗宾逊的答案所示.消息是正确的.

请注意,MSDN说:

其中T :(基类名) - 类型参数必须是或从指定的基类派生.

这解释了为什么它不被允许,因为B它不是源自A

Ada*_*son 10

不,你想要做的事情是不可能的.隐式引用转换与隐式类型转换不同.您的代码定义了隐式类型转换,您可以在其中执行以下操作:

B foo = new B();
A bar = foo;
Run Code Online (Sandbox Code Playgroud)

但是请注意,这foobar现在包含不同的引用.隐式类型转换创建一个新的实例A(按惯例)在逻辑上等价于foo.但关键是它是一个不同的参考.

参考转换将是其中参考本身不发生变化,这意味着所讨论的类型必须要么从(用于类)继承或实现(对于接口)所讨论的类型.如果我这样做:

class A { }
class B : A { }
Run Code Online (Sandbox Code Playgroud)

那么我上面的代码现在将在foo和中保持相同的引用bar.这就是隐式引用转换的含义.相反,明确的引用转换将是向下转换,如下所示:

A foo = new B();
B bar = (B)foo;
Run Code Online (Sandbox Code Playgroud)

同样,引用是相同的,但演员是明确的.

因此,简而言之,MSDN文档更清晰但不太精确.


Ree*_*sey 7

这是不可能的.

隐式转换与类型等价不同.仅仅因为类型可以转换为另一种类型并不意味着它是第二种类型的特定形式.因此,它不适用于通用约束.

这很有道理 - 想想编译器在下面会做什么:

class A 
{
    public void Foo();
}
class B
{
    public static implicit operator A(B me)
    {
        return new A();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,说你有:

public void Bar<T>(T obj) where T : A
{       
    obj.Foo();
    obj.Foo();
    obj.Foo();
}
Run Code Online (Sandbox Code Playgroud)

为了使这个工作与转换(即:允许调用Bar(new B())) - 你必须在该方法内构造一个新的对象实例,因为Foo没有在B上定义.这将是非常意外的,并可能导致一些很难发现错误.在上面,每次方法调用都应该进行转换操作吗?它应该发生一次,并且编译器做一些诡计让它工作?虽然可以想象如何处理这个问题,但没有一种方法是明确的......