在C#泛型 - 不能'类名'转换为'TGenericClass“ [英] Generics in C# - Cannot convert 'classname' to 'TGenericClass'
问题描述
更新:这是不是得到它的编译。现在的问题是,为什么C#编译器允许剧组使用一个接口时,但是当我使用实现相同接口的类不能断定类型。
我收到以下错误:
无法将类型'Amber.BLL.iWeb.Session.AppSession'到'TService '
下面是代码:
公众覆盖TService GetService的< TService>()
{
如果(typeof运算(TService)== typeof运算(IAppSession))
{
AppSession会话=新AppSession();
回报(TService)会议;
}
抛出新的异常(的String.Format(
iWebFactoryProvider无法创建类型{0}的服务。,
typeof运算(TService).Name点));
}
由于恰巧,在 AppSession
类实现了 IAppSession
接口。如果我改变的代码实例 AppSession
行使用的接口,如:
IAppSession会话=新AppSession();
突然间一切编译罚款。我也注意到,它编译罚款,如果我这样做:
AppSession会话=新AppSession();
回报(TService)(IAppSession)会议;
在情况下,它的事项时,GetService的()是压倒其签名声明如下的方法:
public虚拟TService GetService的< TService>()其中TService:类
在总之,我想不通的规则应该是什么在这里,所以我可以知道如何避免以后出现此情况。为什么编译器高兴地投了接口,但不乐意投接口的实现类?
我注意到,这个问题是问类似的问题,但答案不够详细,我理解它是如何应用到我的情况。
为什么使用接口时,但是当我使用实现相同接口的类不能断定类型C#编译器允许投?
块引用>
好问题。考虑以下几点:
公共接口I {}
公众D类{} //注意,D甚至不实现我!
公共类E
{
公共静态M< T>(T T)
{
D D1 =(D)吨; //非法
D D2 =(D)(对象)吨;法律//
D D3 =(D)(I)吨; //法律
}
}
让我们打破你的问题分成三个问题。
为什么直接投从
T
到D
非法的?
块引用>
假设它是合法的。然后
E.M< D>(新D())
会工作得很好;我们就投了T
到D
事实上它是一个D
,所以没有问题。
现在假设我们创建一个完全不同的装配:
类C
{
公共静态明确经营者D(C C){无论}
}
和你打电话
E.M< C>(新C())
在装配..你有什么合理期望发生的呢?你必须键入C
的对象,它被强制转换为D
,并且有一个明确的转换运算符的右边有<从> C
到D
。大多数人会合理预期的显式转换运营商将被调用。
但是,如何在地球上是应该的编译<$ C的主体的情况下实现的编译器$ C> M 的是有人在将来可能会以完全不同的组件创建一个类
C
的?编译器有没有办法编译M
时,将呼叫发射到转换操作符。因此,我们有三种选择:
- 请投运营商有时会使用显式转换运营商,有时没有,这取决于您是否是在一个通用或不是。
- 请转换操作符的再次运行时启动编译器的寻找可能已在不同的组件添加了原代码被编译后显式转换运营商。
- 不允许在首位的演员。
在总之,我们的选择是:(1 )使仿制药不一致的;(2)使仿制药缓慢和不可预知的,或者(3)禁止在已经工作的对的泛型的功能。这是一个容易做出的选择;我们选择了(3)。
如果您希望(2),你可以把它在C#4;
动态
在运行时再次启动编译器和工程是否存在一个显式转换操作符。
为什么通过对象合法的吗?
的距离T
间接投地D
块引用>
由于现在还没有用户定义的转换可能是相关的;从未有从对象到任何一个用户定义的转换。
为什么从
T
间接投以D
通过I
合法吗?
块引用>
由于现在还没有用户定义的转换可能是相关的;从未有从任何东西的接口的用户定义的转换。
奖金的问题:
但
D
甚至不落实I
! ?这是怎么回事与
块引用>
一个派生类
D
的可能:F级:D,I {}
...
E.M< D>(新型F ());
现在
T
可以转换为I
,因为它的可能的实施I
和I
可强制转换为D
,因为它的可能的是˚F
。
如果
D
是密封
那么这将不会是法律从投我
到D
,因为那么不可能是一个派生˚F
键入UPDATE: This isn't about getting it to compile. The question is, why does the C# compiler allow the cast when using an interface, but it can't figure out the type when I use a class that implements the same interface.
I am getting the following error:
Cannot convert type 'Amber.BLL.iWeb.Session.AppSession' to 'TService'
Here is the code:
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 ) ); }
As it so happens, the
AppSession
class implements theIAppSession
interface. If I change the line of code that instantiatesAppSession
to use the interface, like this:IAppSession session = new AppSession();
suddenly everything compiles fine. I also note that it compiles fine if I do this:
AppSession session = new AppSession(); return (TService) (IAppSession) session;
In case it matters, the GetService() is overriding a method whose signature is declared like this:
public virtual TService GetService<TService>() where TService : class
In short, I can't figure out what the rules should be here so I can know how to avoid this situation in the future. Why was the compiler happy to cast the interface, but not happy to cast the interface's implementing class?
I note that this question is asking about a similar issue, but the answer isn't detailed enough for me to understand how it applies to my situation.
解决方案Why does the C# compiler allow the cast when using an interface, but it can't figure out the type when I use a class that implements the same interface?
Good question. Consider the following:
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 } }
Let's break your question up into three questions.
Why is the cast directly from
T
toD
illegal?Suppose it were legal. Then
E.M<D>(new D())
would work just fine; we'd cast theT
toD
and in fact it is aD
, so no problem.Now suppose we create an entirely different assembly with:
class C { public static explicit operator D(C c) { whatever } }
And you call
E.M<C>(new C())
in that assembly.. What do you reasonably expect to happen? You have an object of typeC
, it is being cast toD
, and there is an explicit conversion operator right there fromC
toD
. Most people would reasonably expect that the explicit conversion operator would be called.But how on earth is the compiler supposed to realize when compiling the body of
M
that someone in the future might create a classC
in a completely different assembly? The compiler has no way to emit the call to the conversion operator when compilingM
. So we have three choices:
- Make cast operators sometimes use explicit conversion operators and sometimes not, depending on whether you're in a generic or not.
- Make cast operators start the compiler again at runtime to look for explicit conversion operators that might have been added in different assemblies after the original code was compiled.
- Disallow the cast in the first place.
In short, our choices are (1) make generics inconsistent, (2) make generics slow and unpredictable, or (3) disallow a feature that is already working against genericity. This is an easy choice to make; we chose (3).
If you want (2), you can have it in C# 4;
dynamic
starts the compiler again at runtime and works out whether there is an explicit conversion operator.Why is the cast indirectly from
T
toD
via object legal?Because now no user-defined conversion can be relevant; there is never a user-defined conversion from object to anything.
Why is the cast indirectly from
T
toD
viaI
legal?Because now no user-defined conversion can be relevant; there is never a user-defined conversion from an interface to anything.
Bonus question:
But
D
does not even implementI
! What's up with that?A derived class of
D
might:class F : D, I {} ... E.M<D>(new F());
Now
t
can be cast toI
because it might implementI
, andI
can be cast toD
because it might beF
.If
D
weresealed
then it would not be legal to cast fromI
toD
because then there could not possibly be a derivedF
type.这篇关于在C#泛型 - 不能'类名'转换为'TGenericClass“的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!