如何在C#中进行静态转换?

时间:2010-10-08 21:19:00

标签: c# type-conversion

鉴于这样的几种类型:

interface I {}
class C : I {}

如何进行静态类型转换?我的意思是:我如何以在编译时检查的方式更改其类型?

在C ++中,您可以static_cast<I*>(c)。在C#中,我能做的最好的事情是创建一个备用类型的临时变量并尝试分配它:

var c = new C();
I i = c;  // statically checked

但是这会阻止流畅的编程。我必须创建一个新的变量来进行类型检查。所以我已经确定了这样的事情:

class C : I
{
    public I I { get { return this; } }
}

现在我可以通过调用c.I静态将C转换为I.

在C#中有更好的方法吗?

(如果有人想知道我为什么要这样做,那是因为我使用显式接口实现,并且从另一个成员函数中调用其中一个需要首先转换为接口类型,否则编译器找不到方法。)

更新

我想出的另一个选项是对象扩展:

public static class ObjectExtensions
{
    [DebuggerStepThrough]
    public static T StaticTo<T>(this T o)
    {
        return o;
    }
}

所以((I)c).Doit()也可能是c.StaticTo<I>().Doit()。嗯...可能仍然坚持简单演员。想想我还是会发布这个其他选项。

4 个答案:

答案 0 :(得分:5)

简单地施展它:

(I)c

编辑示例:

var c = new C();

((I)c).MethodOnI();

答案 1 :(得分:2)

var c = new C(); 
I i = c;  // statically checked

等于

I i = new C();

答案 2 :(得分:2)

编写一个扩展方法,使用您在UPDATE中提到的技巧:

public static class ObjectExtensions
{
    public static T StaticCast<T>(this T o) => o;
}

使用:

things.StaticCast<IEnumerable>().GetEnumerator();

如果thingsIEnumerable<object>,则编译。如果thingsobject,则会失败。

// Compiles (because IEnumerable<char> is known at compiletime
// to be IEnumerable too).
"adsf".StaticCast<IEnumerable>().GetEnumerator();

// error CS1929: 'object' does not contain a definition for 'StaticCast'
// and the best extension method overload
// 'ObjectExtensions.StaticCast<IEnumerable>(IEnumerable)'
// requires a receiver of type 'IEnumerable'
new object().StaticCast<IEnumerable>().GetEnumerator();

为什么要使用静态演员?

重构过程中的一个常见做法是继续进行更改,然后验证您的更改未导致任何回归。您可以通过各种方式和不同阶段检测回归。例如,某些类型的重构可能会导致API更改/破坏,并且需要重构代码库的其他部分。

如果您的代码的一部分期望接收在编译时应该知道的类型(ClassA)以实现接口(IInterfaceA)并且该代码想要直接访问接口成员,则可能必须转向接口类型,例如,访问明确实现的接口成员。如果在重构后, ClassA不再实施IIterfaceA ,则会根据您投放到界面的方式获得不同类型的错误:

  1. C-style强制转换:((IInterfaceA)MethodReturningClassA()).Act();突然变成运行时强制转换并抛出运行时错误。
  2. 分配给显式类型的变量:IInterfaceA a = MethodReturningClassA(); a.Act();会引发编译时错误。
  3. 使用static_cast<T>之类的扩展方法:MethodReturningClassA().StaticCast<IInterfaceA>().Act();会引发编译时错误。
  4. 如果您希望转换为转发并且在编译时可以验证,那么您应该使用强制编译时验证的强制转换方法。这使得代码的原始开发人员有意清楚地编写类型安全代码。编写类型安全代码的好处是可以在编译时更加可验证。通过做一些工作来阐明你对其他开发人员,你自己和编译器选择类型安全的意图,你神奇地得到了编译器帮助验证你的代码并且可以在之前(在编译时)比以后捕获重构的影响(如果你的代码没有碰巧有完整的测试覆盖率,比如运行时崩溃。)

答案 3 :(得分:1)

如果您真的只是在寻找一种方法来查看对象是否实现了特定类型,那么您应该使用as

I i = whatever as i;
if (i == null) // It wasn't

否则,你只是施展它。 (在.NET中没有像C ++那样的多种类型的转换 - 除非你比大多数人需要的更深入,但它更多的是关于WeakReference等等。)

I i = (I)c;

如果您只是想方便地将实现I的任何内容转换为I,那么您可以使用扩展方法或类似方法。

public static I ToI(this I @this)
{
    return @this;
}