更新:这不是要让它编译.问题是,为什么C#编译器在使用接口时允许转换,但是当我使用实现相同接口的类时,它无法弄清楚类型.
我收到以下错误:
Cannot convert type 'Amber.BLL.iWeb.Session.AppSession' to 'TService'
Run Code Online (Sandbox Code Playgroud)
这是代码:
public override TService GetService<TService>()
{
if ( typeof( TService ) == typeof( IAppSession ) )
{
AppSession session = new AppSession();
return (TService) session;
}
throw new Exception( String.Format(
"iWebFactoryProvider cannot create services of type '{0}'.",
typeof( TService ).Name ) );
}
Run Code Online (Sandbox Code Playgroud)
实际上,AppSession
该类实现了IAppSession
接口.如果我更改实例化的代码行AppSession
以使用该接口,如下所示:
IAppSession session = new AppSession();
Run Code Online (Sandbox Code Playgroud)
突然间,一切都很好.我还注意到,如果我这样做,它编译得很好:
AppSession session = new AppSession();
return (TService) (IAppSession) session;
Run Code Online (Sandbox Code Playgroud)
如果重要,GetService()将覆盖一个方法,其签名声明如下:
public virtual TService GetService<TService>() where TService : class
Run Code Online (Sandbox Code Playgroud)
简而言之,我无法弄清楚这里的规则是什么,所以我可以知道将来如何避免这种情况.为什么编译器很乐意转换界面,但不乐意投射界面的实现类?
我注意到这个问题是在询问类似的问题,但答案不够详细,我不能理解它是如何适用于我的情况的.
Eri*_*ert 18
为什么C#编译器在使用接口时允许转换,但是当我使用实现相同接口的类时,它无法弄清楚类型?
好问题.考虑以下:
public interface I {}
public class D {} // Note that D does not even implement I!
public class E
{
public static M<T>(T t)
{
D d1 = (D)t; // Illegal
D d2 = (D)(object)t; // Legal
D d3 = (D)(I)t; // Legal
}
}
Run Code Online (Sandbox Code Playgroud)
让我们把你的问题分成三个问题.
为什么是直接投从
T
到D
违法?
假设它是合法的.然后E.M<D>(new D())
会工作得很好; 我们就投了T
到D
,事实上它是一个D
,所以没有问题.
现在假设我们创建了一个完全不同的程序集:
class C
{
public static explicit operator D(C c) { whatever }
}
Run Code Online (Sandbox Code Playgroud)
你召集E.M<C>(new C())
那个大会..你有理由期待发生什么?您有类型的对象C
,它被强制转换为D
,并没有一个明确的转换运营商那里从C
到D
.大多数人会合理地期望调用显式转换运算符.
但是,如何在地球上时,编译器应该实现编制的身体的时候M
是有人在将来可能会创建一个类C
在一个完全不同的组件?编译时,编译器无法向转换运算符发出调用M
.所以我们有三个选择:
简而言之,我们的选择是(1)使泛型不一致,(2)使泛型变得缓慢和不可预测,或(3)禁止已经起作用于反对泛化的特征.这是一个很容易做出的选择; 我们选择了(3).
如果你想要(2),你可以用C#4; dynamic
在运行时再次启动编译器并确定是否存在显式转换运算符.
为什么投间接地从
T
以D
通过对象是否合法?
因为现在没有用户定义的转换可能是相关的; 从来没有用户定义的从对象到任何东西的转换.
为什么投间接地从
T
以D
通过I
法律?
因为现在没有用户定义的转换可能是相关的; 从来没有用户定义的从接口到任何东西的转换.
奖金问题:
但是
D
甚至没有实施I
!那是怎么回事?
派生类的D
权力:
class F : D, I {}
...
E.M<D>(new F());
Run Code Online (Sandbox Code Playgroud)
现在t
可以转换到I
,因为它可能会实现I
,并且I
可以转换为D
,因为它可能是F
.
如果D
是sealed
那就不合法,从投I
来D
,因为那么不可能是派生F
型.