How to do a static cast in C#?
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:
- C-style cast:
((IInterfaceA)MethodReturningClassA()).Act();
would suddenly become a runtime cast and throw a runtime error. - Assigning to an explicitly-typed variable:
IInterfaceA a = MethodReturningClassA(); a.Act();
would raise a compiletime error. - 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;
}
Related videos on Youtube
Esben von Buchwald
Updated on May 05, 2022Comments
-
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 bec.StaticTo<I>().Doit()
. Hmm...probably will still stick with the simple cast. Figured I'd post this other option anyway. -
Esben von Buchwald over 13 yearsCorrect. Unfortunately, that doesn't address my question.
-
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 over 13 yearsNow 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 over 8 yearsNote that the
as
keyword will work for classes, however, this doesn't work with primitive types such asbool
, so if you need to cast for example anint
to abool
, 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 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 about 8 years@binki:
as
is designed to be a runtime command. You don't want compile time errors in a scenario whereas
makes the best sense. -
binki about 8 yearsThe 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++'sstatic_cast<T>
. If you never intended a cast to need runtime verification, wouldn't you rather a compiletime error? -
John Fisher about 8 yearsIf you're assumptions about the question are correct, then the accepted answer is way off. Casting doesn't provide complete compile-time checking, either.