如何在C#中进行静态转换? [英] How to do a static cast in C#?

查看:58
本文介绍了如何在C#中进行静态转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出如下几种类型:

interface I {}
class C : I {}

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

How can I do a static type cast? By this I mean: how can I change its type in a way that gets checked at compile time?

在C ++中,您可以执行 static_cast< I *>(c).在C#中,我能做的最好的事情就是创建一个备用类型的临时变量,然后尝试为其分配:

In C++ you can do static_cast<I*>(c). In C# the best I can do is create a temporary variable of the alternate type and try to assign it:

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

但这会阻止流畅的编程.我必须创建一个新变量才能进行类型检查.所以我已经决定要这样:

But this prevents fluent programming. I have to create a new variable just to do the type check. So I've settled on something like this:

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

现在,我只需调用 c.I 即可将C静态转换为I.

Now I can statically convert C to I by just calling c.I.

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

Is there a better way to do this in C#?

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

(In case anyone's wondering why I want to do this, it's because I use explicit interface implementations, and calling one of those from within another member function requires a cast to the interface type first, otherwise the compiler can't find the method.)

更新

我想到的另一个选择是对象扩展:

Another option I came up with is an object extension:

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

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

So ((I)c).Doit() could also be c.StaticTo<I>().Doit(). Hmm...probably will still stick with the simple cast. Figured I'd post this other option anyway.

推荐答案

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

Write an extension method that uses the trick you mentioned in your UPDATE:

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

要使用:

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

如果 things 是例如 IEnumerable< object> ,则会进行编译.如果 things object ,则失败.

If things is, e.g., IEnumerable<object>, this compiles. If things is object, it fails.

// 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更改/损坏,并要求重构代码库的其他部分.

Why Use a Static Cast?

One common practice during refactoring is to go ahead and make your changes and then verify that your changes have not caused any regressions. You can detect regressions in various ways and at various stages. For example, some types of refactoring may result in API changes/breakage and require refactoring other parts of the codebase.

如果您的代码的一部分希望接收一种在编译时就应该知道的类型( ClassA ),以实现接口( IInterfaceA ),并且该代码想要访问如果直接使用接口成员,则可能必须转换为接口类型以访问例如显式实现的接口成员.重构后,如果 ClassA 不再实现 IIterfaceA ,则您将得到不同类型的错误,具体取决于您转换为接口的方式:

If one part of your code expects to receive a type (ClassA) that should be known at compiletime to implement an interface (IInterfaceA) and that code wants to access interface members directly, it may have to cast down to the interface type to, e.g., access explicitly implemented interface members. If, after refactoring, ClassA no longer implements IIterfaceA, you get different types of errors depending on how you casted down to the interface:

  1. C样式强制转换:((IInterfaceA)MethodReturningClassA()).Act(); 会突然变成运行时强制转换并抛出运行时错误.
  2. 分配给显式类型的变量: IInterfaceA a = MethodReturningClassA();a.Act(); 会引发编译时错误.
  3. 使用类似 static_cast< T> 的扩展方法: MethodReturningClassA().StaticCast< IInterfaceA>().Act(); 会产生编译时错误./li>
  1. C-style cast: ((IInterfaceA)MethodReturningClassA()).Act(); would suddenly become a runtime cast and throw a runtime error.
  2. Assigning to an explicitly-typed variable: IInterfaceA a = MethodReturningClassA(); a.Act(); would raise a compiletime error.
  3. Using the static_cast<T>-like extension method: MethodReturningClassA().StaticCast<IInterfaceA>().Act(); would raise a compiletime error.

如果您希望自己的转换不正确,并且可以在编译时进行验证,则应该使用强制进行编译时验证的转换方法.这使代码的原始开发人员意图明确地编写类型安全的代码.编写类型安全代码的好处是可以在编译时进行更多验证.通过做一些工作来阐明您打算对其他开发人员,您自己和编译器选择使用类型安全的意图,您可以神奇地获得编译器的帮助来验证代码,并且可以(在编译时)早于(在编译时)捕获重构的后果(例如运行时崩溃(如果您的代码未恰好具有完整的测试范围).

If you expected your cast to be a downcast and to be verifiable at compiletime, then you should use a casting method that forces compiletime verification. This makes the intentions of the code’s original developer to write typesafe code clear. And writing typesafe code has the benefit of being more verifiable at compiletime. By doing a little bit of work to clarify your intention to opt into typesafety to both other developers, yourself, and the compiler, you magically get the compiler’s help in verifying your code and can catch repercussions of refactoring earlier (at compiletime) than later (such as a runtime crash if your code didn’t happen to have full test coverage).

这篇关于如何在C#中进行静态转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆