C#相当于VB.NET的DirectCast?

时间:2010-04-21 14:32:54

标签: c# vb.net casting directcast ctype

C#是否与VB.NET的DirectCast等效?

我知道它有()强制转换和'as'关键字,但那些符合CType和TryCast。

要明确,这些关键字会执行以下操作;

CType /()强制转换:如果它已经是正确的类型,则强制转换它,否则查找类型转换器并调用它。如果未找到类型转换器,则抛出InvalidCastException。

TryCast /“as”关键字:如果是正确的类型,请将其强制转换,否则返回null。

DirectCast :如果是正确的类型,请将其强制转换,否则抛出InvalidCastException。

在我详细说明之后,有些人仍然回答说()是等价的,所以我会进一步扩展为什么不是这样。

DirectCast仅允许在继承树上缩小或扩大转换。它不支持跨越不同分支的转换,如(),即:

C# - 编译并运行:

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

VB.NET - 这不是编译

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

VB.NET与C#代码的等价物是CType:

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

11 个答案:

答案 0 :(得分:11)

很明显,您想要的功能不在C#中。试试这个......

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

或者,即使它与VB不同,也可以这样称呼:

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

答案 1 :(得分:8)

第二次更新

好的,这是一个C#方法,据称基本上做了DirectCast在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;
}

以上方法存在以下问题:

  1. 它有一个where T : class约束,DirectCast没有约束。
  2. 它将其参数设为System.Object - 再次,DirectCast并非如此(至少不是我所知道的。)
  3. 它不必要地使用as(这就是它首先具有class约束的原因);如果不起作用,调用(T)o将抛出InvalidCastException;为什么要使用as检查值是否匹配,只是为了抛出如果你开始使用(T)o路径时会抛出的相同异常?
  4. 该方法实际上可以重写,以提供与DirectCast相同的结果,如下所示:

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

    有趣的观察:真的所有这个方法都是装箱值,然后尝试将其拆箱。换句话说,DirectCast<int>(12.0)实际上与(int)(object)12.0相同(并且要么抛出异常)。实现这一点使得提议的DirectCast<T>方法完全没有必要。

    现在,这是一个示例,说明DirectCast()的转换如何在VB.NET和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
    

    好的,所以一个编译,另一个不编译。但看看那段代码。 当你已经知道某个对象的类型时DirectCast有什么意义呢?这不是一个真实的比较,因为在VB.NET中,没有任何理由可以调用DirectCast像上面的代码一样。 (如果要在VB.NET中将值已知类型为System.Int32 的值转换为类型System.Int64的值,则使用CLng,不是DirectCast。)如果有一个变量类型为System.Object,那么那么就可以使用DirectCast,而下面的代码确实是当量:

    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
    

    所以我在VB.NET中维护DirectCast,在任何实际使用它的情况下(即,在编译时不知道对象的类型),是与C#中的直接() - 样式转换相同。


    编辑:很遗憾,我发布了一些没有编译的VB代码。在重新考虑我说的话之后,我撤回了第二个答案,但保留了第一个答案。

    如果您指的是DirectCast使用未知类型的对象并尝试将其转换为所需类型的用法,则 与C#相同(演员:

    VB:

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

    C#:

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

    这是因为,如果o被输入为System.Object,那么C#中的()操作将尝试将其取消装箱。如果类型不完全匹配,则会失败;例如,如果o是一个装箱的System.Double,则(int)o会抛出异常,因为o 必须取消装箱{{1}之前它可以转换为System.Double(如果你不相信我,请亲自尝试一下!)。


    注意:以下内容不准确,因为System.Int32 执行扩展转换;无论如何,我将其留给后人。

    另一方面,在处理扩展转换和缩小转换时,在C#中使用DirectCast操作比简单转换更有效,正如您所指出的那样(即,您可以{{1} })。在这种情况下,()等同于C#中的普通旧分配:

    VB:

    (int)someDouble

    C#:

    DirectCast

答案 2 :(得分:1)

实际上,如果编译器推断出类型化变量无法转换为其他类型,则编译器会捕获DirectCast违规

这些是实际的等价物:

double d = 10;
int i = (int)d;

Dim d As Double = 10
Dim i As Integer = d

注意这个结构的危险性,当你只是在VB.NET中将double赋值为double时,double会被意外地缩小为整数。

而C#程序员获得编译时的安全性,不小心缩小变量.NET。 VB.NET程序员必须始终将DirectCast作为一种安全的编程习惯来应对

这些是实际的等价物:

// will not compile, cannot convert double to int

double d = 10;
int i = d; 

' will not compile, cannot convert double to int

Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer) 

<强> [编辑]

@Dan Tao:

不需要在C#中使用DirectCast,运行时也可以防止加载long到整数值。这就是csauve所争辩的,C#没有DirectCast,DirectCast可以阻止分配不同类型的变量,而“因为”C#没有这个DirectCast,它会在分配不同类型时默默地出错。但正如你所看到的那样,情况并非如此,C#的强制转换完全与DirectCast相同。这将导致 InvalidCastException 运行时错误:

long l = 10;
object o = l;
int i = (int)o;

这也会导致与上面相同的运行时错误

Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = DirectCast(o, Integer)

现在,这就是“有趣”部分的用武之地,使用VB.NET,您必须记住许多关键字才能完成某些任务。在C#中,如果给定的关键字可以在另一个场景中使用(比如在这一个向下转换变量),他们就不会发明另一个关键字来实现它。

在C#中你只需要这样做:

long l = 10;
object o = l;
int i = (int)(long)o;

在VB.NET中如果你真的想要转发变量,并希望采用正交方式来做,即只记住一个关键字,你必须这样做:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = DirectCast(DirectCast(o, Long), Integer)

但那不会编译,那么如何实现向下转换为整数?你必须记住VB.NET的其他关键字。而在C#中,它是正交的,使用此构造(typehere)的unbox变量,您还使用相同的构造(typehere)进行向下/向上转换。在VB.NET中,从对象加载值和向下转换它之间存在根本性的脱节。所以在VB.NET中,你必须这样做:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = CType(o, Integer)

嗯......我认为csauve混淆源于C#多次使用(typehere),首先它用于向下转换;第二,相同的构造(检查这篇文章的第一部分,object o = l)也用于从对象中取消装箱值,这可以肯定它具有DirectCast的安全类型转换行为,它们是相同的!

这种向下倾斜......

long l = 1;
int i = (int) l;

......不等同于:

Dim l As Long = 1
Dim i As Integer = DirectCast(l, Integer)

如果要执行向下转换,则必须执行此操作:

Dim l As Long = 1
Dim i As Integer = CInt(l) ' can also use CType

现在,如果一个VB.NET程序员按意图编程,而不是在编码时困,为什么他会在完全意识到它不能分配不同类型时使用DirectCast?如果VB.NET程序员真正想要的是低调,他不应该首先尝试DirectCast。现在VB.NET程序员在发现DirectCast不能用于向下转换时,必须退回他写的内容并用CInt(或CType)替换它

答案 3 :(得分:1)

您可以自己实施:

static T CastTo<T>(this object obj) { return (T)obj; }

可用如下:

3.5.CastTo<int>(); //throws InvalidCastException.

这有效且不涉及用户定义的转换器,因为泛型在运行时被“解析”但类型转换在编译时被解析 - 框架实际上并不为每个{{1生成不同的实现而是共享类似T的实现,因此运行时没有解析自定义转换的信息。

答案 4 :(得分:1)

VB.NET:

Dim xxx as label = Directcast(sender, label)

C#:

label xxx = (label)sender;

答案 5 :(得分:0)

C#中有两种类型的强制转换。没有额外的代码,就没有C#中的DirectCast关键字。没有自己创建的最接近的是使用()

你有:

My_Object c = (My_Object)object

My_Object c = object as My_Object

在第一个中,如果转换失败,则会抛出错误。你说,“我知道这个对象是什么,如果不是,就会出现问题。”

在第二个中,c在可能的情况下被赋值为null(null不能分配给值类型)。在这一个你说的是“我想我知道这是什么,但如果不是,不要抛出错误,因为没有什么可能是错的。”

解释演员的其他帖子:

What is the difference between explicit and implicit type casts?

答案 6 :(得分:0)

您是否真的尝试运行示例代码?

...关于

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

...你假定它会运行。它也没有运行

答案 7 :(得分:0)

让我试着试一试。

首先,让我明白这一点。这不会编译:

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

VB的CType

在VB中,您将使用:

Dim s as String = "10"
Dim i as Integer = CType(s, Integer)

在C#中,我会使用:

string s = "10";
int i = Convert.ToInt32(s);

VB的DirectCast

  

如果是正确的类型,请投下它,   否则扔一个   InvalidCastException的。

     

直接施法只能上升或下降a   分支,永远不会与众不同   之一。

根据该解释,它将直接等同于C#cast。但是在C#中,您只需要指定强制转换运算符。施放是完全可选的。例如:

// casting down
object t = "some random string needing to be casted down";
string s = (string) t;
// casting up
object a = s;
// explicitly casting up although it's totally optional
object b = (object) s;

C#cast不会查找任何类型转换器。它只会查找您尝试转换为的类型的任何已定义的显式/隐式运算符重载。


VB的TryCast

您已经正确理解,这相当于C#作为关键字。

答案 8 :(得分:0)

我认为这种情况总结了DirectCast错误的编译时类型检查非对象(对象关键字)类型的安全性,并且只是为了退格。

float f = 10;
long l = f;

Option Strict On    
Dim f As Single = 10
Dim l As Long = f

C#编码器在发现float不能直接赋值给long并且不能编译时,会这样做:

long l = (long)f;

哪个是正确的。

现在,让我们转向我们的VB.NET编码器,一旦发现float不能分配给long并且不会编译,就会尝试这样做:

Dim l As Long = DirectCast(f, Long)

几秒钟后......

VB.Net程序员:“请让我做我的出价,请编译,请...... !!!”

稍后浏览了一些Googling-fu和MSDN:

VB.NET程序员:“啊......所以我必须使用这个CLng或CType构造来构建变量”

Dim l As Long = CLng(f)

这就是我对DirectCast的意思,它具有错误的编译时类型检查安全性。如果程序员不知道应该在何时何地使用DirectCast,那么DirectCast只是要退格。 DirectCast是一种安全毯,不会一直磨损。

如果DirectCast毕竟不会被使用,那么它在这种情况下有多大用处?


<强> [编辑]

@Jules

我并不是说所有的VB.NET程序员都不知道DirectCast的实际用途是什么,他们中的一些人确实知道DirectCast只是用于对象类型(和盒装的原始类型)对象)。

VB.NET编码器将现有的C#代码重新编码为VB.NET的一种情况将得出错误的结论,与预期的(无论是否正确)语言相互对称。

当他在代码中看到这个构造......

TextBox txt = (TextBox)sender;

......他会将其翻译成:

Dim txt As TextBox = DirectCast(sender, TextBox)

哪个是正确的。

现在,因为我们程序员喜欢对称性,我们中的一些人(如果我不知道CLng,我可能也会这样)会倾向于转换此代码...

/* numbers are stored in file as float(component's file structure 
is designed by 3rd party company) */
float f = file.ReadFloat(0); 
long l = (long)f; // but we don't care about using the fractional part

......对此:

Dim f As Single = file.ReadFloat(0)
Dim l As Long = DirectCast(f, Long)

如果一个C#人员将C#代码转换为VB.NET,他会因为明显缺乏对称性而感到沮丧。

但是对于一个负责将C#代码转换为VB.NET的VB.NET人来说,他会觉得C#编译器不会捕获不兼容的类型赋值,而VB.NET会抓住它。现在,对于那个明显的发现,将吹嘘VB.NET功能给他的同事和一些论坛。

但是,以免VB.NET程序员错误地推断出第一个代码的意图。 上面的C#的代码片段开始了这样的生活最初是这样编写的:

float f = file.ReadFloat(0); 
long l = f; 

而且这不会编译,C#编译器捕获不兼容的类型赋值,同样的情况是,带有Option Strict On的等效VB.NET也不会编译(虽然只会编译当Option Strict设置为On时,太宽松了。所以我们需要使用(long)对float进行长期类型转换。成为:long l = (long)f;

现在将一个变量类型转换为另一个兼容类型,与我们转换此代码的方式相同......

TextBox txt = (TextBox)sender;

...到这段代码:

Dim txt As TextBox = DirectCast(sender, Textbox)

我们必须转换此代码......

long l = (long)f; // will compile

...到这段代码:

Dim l As Long = DirectCast(f, Long) ' will not compile

但是,唉,在兼容的原始类型之间进行转换时不会编译,这就是DirectCast不足之处。它没有为上面的C#代码提供任何对称性,它不能用于转换兼容的原始类型,尽管其名称为直接演员

我看到它的方式,DirectCast应命名为 CastObject ,因为无论如何它只能在对象类型(以及在对象中装箱的基本类型)之间进行转换。 DirectCast真的没有业务分配兼容的基本类型(整数,双精度,以及它们的更低和更高的对应物)。在兼容的基元类型之间进行分配时,DirectCast不再有用,尤其是无论如何都会对它进行退格,并用适当的替换它。

或者我看到它的另一种方式,应该修改DirectCast构造,以便它可以像以往那样使用新旧语言的方式来转换兼容类型,例如: C,C ++,C#,Java,Delphi,D等。这样做,它将为类型转换提供VB.NET与其他语言的显着对称性。这样做,我们也可以抛弃(假设只是,我们不能使其他程序失败,依赖于旧函数)所有名称不直接映射到其类型的函数(例如CInt,CDbl,CSng等),我们将只使用DirectCast代替它们。

答案 9 :(得分:0)

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.

答案 10 :(得分:-1)

()铸造应该是相同的;它会抛出InvalidCastException。只需在C#中尝试:

 string t = "hello";
 object x = t;
 int j = (int) x;
相关问题