C#'s equivalent to VB.NET's DirectCast?

2020-02-08 05:02发布

Does C# have an equivalent to VB.NET's DirectCast?

I am aware that it has () casts and the 'as' keyword, but those line up to CType and TryCast.

To be clear, these keywords do the following;

CType/() casts: If it is already the correct type, cast it, otherwise look for a type converter and invoke it. If no type converter is found, throw an InvalidCastException.

TryCast/"as" keyword: If it is the correct type, cast it, otherwise return null.

DirectCast: If it is the correct type, cast it, otherwise throw an InvalidCastException.

After I have spelled out the above, some people have still responded that () is equivalent, so I will expand further upon why this is not true.

DirectCast only allows for either narrowing or widening conversions on the inheritance tree. It does not support conversions across different branches like () does, i.e.:

C# - this compiles and runs:

//This code uses a type converter to go across an inheritance tree
double d = 10;
int i = (int)d;

VB.NET - this does NOT COMPILE

'Direct cast can only go up or down a branch, never across to a different one.
Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer)

The equivalent in VB.NET to my C# code is CType:

'This compiles and runs
Dim d As Double = 10
Dim i As Integer = CType(d, Integer)

11条回答
Lonely孤独者°
2楼-- · 2020-02-08 05:36

VB.NET:

Dim xxx as label = Directcast(sender, label)

C#:

label xxx = (label)sender;
查看更多
smile是对你的礼貌
3楼-- · 2020-02-08 05:36

You have two types of cast in C#. Without additional code there is no equivalent to the DirectCast keyword in C#. The closest you have without creating it yourself is to use ().

You have:

My_Object c = (My_Object)object

and

My_Object c = object as My_Object

In the first one, if the cast fails, it throws an error. You are saying, "I know what this object is, and if it is not, there is something wrong."

In the second, c is assigned the value null where possible (null can't be assigned to value types). In this one you are saying "I think I know what this one is, but if not don't throw an error, because nothing might be wrong."

Other post explaining casting:

What is the difference between explicit and implicit type casts?

查看更多
孤傲高冷的网名
4楼-- · 2020-02-08 05:36

DirectCast and () do not always generate the same IL, so I think this is a difference between the VB and C# compilers.

AFAICT, reference types get cast using the castclass IL instruction, while for value types the compiler generates the relevant IL depending on the input types.

In C#, casting from double to integer emits the conv.i4 IL instruction, which will cheerfully overwrite the sign bit or whatever in the output, if the value is too large. In VB, it's a compilation error.

Interestingly, if you use an intermediate object variable to hold the double, then the cast will fail for both C# and VB... but at runtime. Both compilers emit an unbox instruction instead of trying to do a conversion.

查看更多
相关推荐>>
5楼-- · 2020-02-08 05:38

The () casting should be the same; it throws an InvalidCastException. Just try this in C#:

 string t = "hello";
 object x = t;
 int j = (int) x;
查看更多
我命由我不由天
6楼-- · 2020-02-08 05:44

SECOND UPDATE:

OK, here's a C# method that's been proposed to allegedly do basically what DirectCast does in VB.NET.

static T DirectCast<T>(object o) where T : class
{
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Here are the problems with the above method:

  1. It has a where T : class constraint, which DirectCast does not.
  2. It boxes its argument as a System.Object -- again, not true of DirectCast (at least not that I'm aware of).
  3. It uses as unnecessarily (which is why it has the class constraint in the first place); calling (T)o will throw an InvalidCastException if it doesn't work; why check if the value matches up using as, only to throw the same exception that would've been thrown if you'd gone the (T)o route to begin with?

The method could really be rewritten to provide the same results as DirectCast as follows:

static T DirectCast<T>(object o) {
    return (T)o;
}

Funny observation: really all this method is doing is boxing a value and then attempting to unbox it. In other words, DirectCast<int>(12.0) would really be the same as (int)(object)12.0 (and either would throw an exception). Realizing this makes the proposed DirectCast<T> method pretty unnecessary altogether.

Now, here's an example of how DirectCast and casting with () are "different" between VB.NET and C#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile '

C#:

int i = 12;
long l = i; // DOES compile

OK, so one compiles, the other doesn't. But look at that code. What's the point of DirectCast when you already know an object's type? This is not a realistic comparison, because in VB.NET there'd never be any reason to call DirectCast like the code above does. (If you wanted to convert a value known to be of type System.Int32 to a value of type System.Int64 in VB.NET, you'd use CLng, not DirectCast.) If there were a variable typed as System.Object in there, then it would make sense to use DirectCast, and the below code would indeed be equivalent:

VB:

Dim i As Integer = 12
Dim o As Object = i
Dim l As Long = DirectCast(o, Long) ' compiles, throws an exception '

C#:

int i = 12;
object o = i;
long l = (long)o; // compiles, throws an exception

So I maintain that DirectCast in VB.NET, in any scenario in which it actually makes sense to use it (i.e., when the type of an object is not known at compile time), is the same as a straight ()-style cast in C#.


EDIT: Well, shame on me for posting some VB code that didn't compile. After reconsidering what I was saying, I withdraw my second answer but maintain the first.

If you're referring to the usage of DirectCast where you take an object of unknown type and try to cast it to the desired type, then it is the same as C#'s () cast:

VB:

Dim o As Object = SomeObject()
Dim i As Integer = DirectCast(o, Integer)

C#:

object o = SomeObject();
int i = (int)o;

This is because, if o is typed as a System.Object, then the () operation in C# will attempt to unbox it. This will fail if the types don't match exactly; for instance, if o is a boxed System.Double, then (int)o will throw an exception because o must be unboxed as a System.Double before it can be converted to a System.Int32 (if you don't believe me, try it out for yourself!).


Note: the below is inaccurate because DirectCast does not perform widening conversions; in any case, I'm leaving it for posterity.

On the other hand, when dealing with widening vs. narrowing conversions, using the () operation in C# does more work than simply casting, as you've pointed out (i.e., you can do (int)someDouble). In this scenario, DirectCast is equivalent to plain old assignment in C#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile, actually '

C#:

int i = 12;
long l = i;
查看更多
登录 后发表回答