首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Sealed关键字会影响编译器对类型转换的看法

Sealed关键字会影响编译器对类型转换的看法
EN

Stack Overflow用户
提问于 2012-01-18 23:16:14
回答 3查看 489关注 0票数 19

我有一种情况,我希望编译器的行为得到解释。给出一小段代码:

代码语言:javascript
复制
interface IFoo<T>
{
    T Get();
}

class FooGetter : IFoo<int>
{
    public int Get()
    {
        return 42;
    }
}

以下代码将编译并运行:

代码语言:javascript
复制
static class FooGetterGetter
{
    public static IFoo<T> Get<T>()
    {
        return (IFoo<T>)new FooGetter();
    }
}

如果我们更改了Foo类的签名并添加了sealed关键字:

代码语言:javascript
复制
sealed class FooGetter : IFoo<int> // etc

然后,我在下面的行上得到一个编译器错误:

代码语言:javascript
复制
 return (IFoo<T>)new FooGetter();

地址为:

无法将类型“MyNamespace.FooGetter”转换为“MyNamespace.IFoo”

有人能解释一下这里发生的关于sealed关键字的事情吗?这是Visual Studio2010中针对.NET 4项目的C# 4。

更新:有趣的是,当我想知道为什么下面的代码在应用sealed时会修复它时,我偶然发现了这部分行为:

代码语言:javascript
复制
return (IFoo<T>)(IFoo<int>)new FooGetter();

更新:只是为了澄清,当请求的T类型与具体类型使用的T类型相同时,它都运行得很好。如果类型不同,则强制转换在运行时会失败,并显示如下内容:

无法将'MyNamespace.StringFoo‘类型的对象强制转换为'MyNamespace.IFoo`1System.Int32’类型

在上面的例子中,StringFoo : IFoo<string>和调用者请求获取一个int

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-18 23:33:01

因为FooGetterIFoo<int>的显式实现,而不是一般的IFoo<T>实现。因为它是密封的,所以如果T不是int,编译器就知道没有办法将它转换为泛型IFoo<T>。如果它不是密封的,如果T不是int,编译器将允许它在运行时编译并抛出异常。

如果您尝试将它与int (例如FooGetterGetter.Get<double>();)以外的任何对象一起使用,则会得到一个异常:

无法将'MyNamespace.FooGetter‘类型的对象强制转换为’MyNamespace.IFo`1System.Double‘类型。

我不确定的是,为什么编译器不会为非密封版本生成错误。像new FooGetter()这样子类FooGetter如何提供实现IFoo<{something_other_than_int}>的任何东西

更新:

对于Dan BryantAndras Zoltan,都有从构造函数返回派生类的方法(或者更准确地说,编译器通过分析属性来返回不同的类型)。因此从技术上讲,如果类不是密封的,这是可行的。

票数 8
EN

Stack Overflow用户

发布于 2012-01-19 01:21:09

当一个类处于未密封状态时,任何派生类都可以实现IFoo<T>

代码语言:javascript
复制
class MyClass : FooGetter, IFoo<double> { }

FooGetter被标记为密封时,编译器知道除了IFoo<int>之外,对于FooGetter不可能存在任何其他的IFoo<T>实现。

这是一个很好的行为,它允许您在编译时而不是运行时捕获代码中的问题。

(IFoo<T>)(IFoo<int>)new FooGetter();工作的原因是因为您现在将您的密封类表示为IFoo<int>,它可以由任何东西实现。这也是一个很好的解决办法,因为你不是偶然的,而是故意覆盖编译器检查。

票数 4
EN

Stack Overflow用户

发布于 2012-10-15 05:02:39

只是补充一下现有的答案:这与使用的泛型没有任何关系。

考虑这个更简单的例子:

代码语言:javascript
复制
interface ISomething
{
}

class OtherThing
{
}

然后说(在一个方法中):

代码语言:javascript
复制
OtherThing ot = XXX;
ISomething st = (ISomething)ot;

工作得很好。编译器不知道OtherThing是否可能是ISomething,所以当我们说它会成功时,它会相信我们。但是,如果我们将OtherThing更改为密封类型(即sealed class OtherThing { }struct OtherThing { }),则不再允许强制转换。编译器知道它不能很好地运行(除非otnull,但是C#的规则仍然不允许从密封类型到未由该密封类型实现的接口的转换)。

关于问题的更新:编写(IFoo<T>)(IFoo<int>)new FooGetter()与编写(IFoo<T>)(object)new FooGetter()没有太大区别。你可以通过一些中间类型来“允许”任何类型的转换(有泛型或没有泛型),这些中间类型肯定/可能是你想要转换的两种类型的祖先。它与下面的模式非常相似:

代码语言:javascript
复制
void MyMethod<T>(T t)    // no "where" constraints on T
{
  if (typeof(T) = typeof(GreatType))
  {
    var tConverted = (GreatType)(object)t;
    // ... use tConverted here
  }
  // ... other stuff
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8912542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档