c# - C# 中的泛型 - 无法将 'classname' 转换为 'TGenericClass'

标签 c# generics

更新:这与让它编译无关。问题是,为什么 C# 编译器在使用接口(interface)时允许转换,但当我使用实现相同接口(interface)的类时却无法确定类型。

我收到以下错误:

Cannot convert type 'Amber.BLL.iWeb.Session.AppSession' to 'TService'   

代码如下:

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

碰巧,AppSession 类实现了IAppSession 接口(interface)。如果我更改实例化 AppSession 的代码行以使用该接口(interface),如下所示:

IAppSession session = new AppSession();

突然一切都编译好了。我还注意到,如果我这样做,它编译得很好:

AppSession session = new AppSession();
return (TService) (IAppSession) session;

以防万一,GetService() 覆盖了一个方法,其签名声明如下:

public virtual TService GetService<TService>() where TService : class

简而言之,我无法弄清楚这里应该有什么规则,以便我知道将来如何避免这种情况。为什么编译器乐于强制转换接口(interface),而不乐于强制转换接口(interface)的实现类?

我注意到 this question问了一个类似的问题,但答案不够详细,我无法理解它如何适用于我的情况。

最佳答案

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?

好问题。请考虑以下事项:

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

让我们将您的问题分成三个问题。

Why is the cast directly from T to D illegal?

假设它是合法的。然后 E.M<D>(new D())会工作得很好;我们投了 TD事实上它是一个D ,所以没问题。

现在假设我们创建一个完全不同的程序集:

class C 
{
    public static explicit operator D(C c) { whatever }
}

你调用E.M<C>(new C())在那个集会中.. 你合理地期望会发生什么?您有一个 C 类型的对象, 它被转换为 D ,并且有一个来自 C 的显式转换运算符就在那里D .大多数人会合理地期望会调用显式转换运算符。

但是编译器在编译 M 的主体时应该如何实现 将来有人可能会创建一个类 C在一个完全不同的程序集中?编译器在编译时无法发出对转换运算符的调用 M .所以我们有三个选择:

  1. 使强制转换运算符有时使用显式转换运算符,有时不使用,具体取决于您是否处于泛型中。
  2. 使转换运算符在运行时再次启动编译器以查找在编译原始代码后可能已添加到不同程序集中的显式转换运算符。
  3. 首先禁止强制转换。

简而言之,我们的选择是 (1) 使泛型不一致,(2) 使泛型缓慢且不可预测,或 (3) 禁止已经在反对泛型的功能。这是一个容易做出的选择;我们选择了(3)。

如果你想要 (2),你可以在 C# 4 中拥有它; dynamic在运行时再次启动编译器并计算是否存在显式转换运算符。

Why is the cast indirectly from T to D via object legal?

因为现在没有用户定义的转换是相关的;从来没有用户定义的从对象到任何东西的转换。

Why is the cast indirectly from T to D via I legal?

因为现在没有用户定义的转换是相关的;从来没有用户定义的从接口(interface)到任何东西的转换。

奖励问题:

But D does not even implement I! What's up with that?

D 的派生类可能:

class F : D, I {}
...
E.M<D>(new F());

现在t可以转换为 I因为它可能实现I , 和 I可以转换为 D因为它可能F .

如果Dsealed那么从 I 转换是不合法的至 D因为那样就不可能有派生的 F类型。

关于c# - C# 中的泛型 - 无法将 'classname' 转换为 'TGenericClass',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9501439/

相关文章:

c# - 在 C# 中清理用户输入 - 最干净的方法?

c# - UWP 应用程序中的自引用泛型类型约束和 XAML

c# - 如何在 conversionType 为十进制且输入为 "40.00"时使用 Convert.ChangeType()

java - 具有多线程和实例共享的泛型

c# - Entity Framework 代码优先 : Migrate a database known only at runtime

c# - 图像在 Win8/Win10 中呈现,但在 Win7 中不呈现

c# - 在 iOS 上为 .NET Maui 应用程序创建安装程序 - Visual Studio

c# - CheckedListBox 检查列表项属性绑定(bind)到类中的字段

java - 在Java SpringBoot中,可以有一个通用的起始节点并稍后分配类型吗?

swift - 我如何在 Swift 中初始化这种包含属性但没有构造函数的枚举?