How to do a static cast in C#?

17,230

Solution 1

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

To use:

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

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

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.

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-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).

Solution 2

Simply cast it:

(I)c

Edit Example:

var c = new C();

((I)c).MethodOnI();

Solution 3

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

equals to

I i = new C();

Solution 4

If you're really just looking for a way to see if an object implements a specific type, you should use as.

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

Otherwise, you just cast it. (There aren't really multiple types of casting in .NET like there are in C++ -- unless you get deeper than most people need to, but then it's more about WeakReference and such things.)

I i = (I)c;

If you're just looking for a convenient way to turn anything implementing I into an I, then you could use an extension method or something similar.

public static I ToI(this I @this)
{
    return @this;
}
Share:
17,230

Related videos on Youtube

Esben von Buchwald
Author by

Esben von Buchwald

Updated on May 05, 2022

Comments

  • Esben von Buchwald
    Esben von Buchwald almost 2 years

    Given a couple types like this:

    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?

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

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

    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.)

    UPDATE

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

    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.

  • Esben von Buchwald
    Esben von Buchwald over 13 years
    Correct. Unfortunately, that doesn't address my question.
  • Esben von Buchwald
    Esben von Buchwald over 13 years
    (facepalm)..well that was obvious, why didn't I try that? Ugly but it works. Thanks. :)
  • Esben von Buchwald
    Esben von Buchwald over 13 years
    Now that I think about it more, there is one small way that the compiler will skip the static type check. Say you start with an Object. It can be cast to anything with no errors, whereas the extension method StaticTo<T> I just added above to the question would catch such a bad cast. A minor point.
  • Seldom 'Where's Monica' Needy
    Seldom 'Where's Monica' Needy over 8 years
    Note that the as keyword will work for classes, however, this doesn't work with primitive types such as bool, so if you need to cast for example an int to a bool, you'll have to use the ugly C-style casting that is so strongly discouraged now in C++ (which poor OP clearly didn't expect in a language as new as C#) OR you can take the second approach shown above, or use the neat templated approach provided in OP's update.
  • binki
    binki about 8 years
    as will perform a dynamic cast sometimes without throwing a compiletime error. Your answer is hiding the real gem at the end ;-)
  • John Fisher
    John Fisher about 8 years
    @binki: as is designed to be a runtime command. You don't want compile time errors in a scenario where as makes the best sense.
  • binki
    binki about 8 years
    The question seems to be getting at how to cast an object to a base class/interface in a way that can be verified at compiletime. Because as will silently switch between performing compiletime and runtime type checking, it doesn't safely force a compiletime check like C++'s static_cast<T>. If you never intended a cast to need runtime verification, wouldn't you rather a compiletime error?
  • John Fisher
    John Fisher about 8 years
    If you're assumptions about the question are correct, then the accepted answer is way off. Casting doesn't provide complete compile-time checking, either.