C#相当于VB.NET的DirectCast?

C#有和VB.NET的DirectCast相同的function吗?

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

要清楚的是,这些关键字执行以下操作;

CType /()强制转换 :如果它已经是正确的types,则转换它,否则查找types转换器并调用它。 如果没有findtypes转换器,则抛出一个InvalidCastException。

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

DirectCast :如果是正确的types,则抛出它,否则抛出InvalidCastException。

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

DirectCast只允许在inheritance树上缩小或扩大转换。 它不支持像()这样的不同分支之间的转换,即:

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) 

看来很清楚,你想要的function不在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; } 

第二次更新

好的,这里提供了一个C#方法,据称这个方法基本上可以做到VB.NET中DirectCastfunction。

 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 (至less不是我所知道的)。
  3. 它不必要地使用(这就是为什么它首先有class限制); 调用(T)o如果不起作用将抛出InvalidCastException ; 为什么要检查值是否与使用as相匹配,只是抛出如果你走了(T)o路由开始的同样的exception?

该方法可以真正重写,以提供与DirectCast相同的结果,如下所示:

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

有趣的观察:真正的所有这个方法是拳击一个值,然后试图解开它。 换句话说, DirectCast<int>(12.0)实际上和(int)(object)12.0 (两者都会抛出一个exception)。 意识到这一点使得build议的DirectCast<T>方法完全没有必要。

现在,下面是VB.NET和C#之间DirectCast和cast ()的“不同”的例子:

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 

好的,所以一个编译,另一个不。 但看看这个代码。 当你已经知道对象的types时, DirectCast什么意义? 这不是一个现实的比较,因为在VB.NET中没有任何理由像上面的代码那样调用DirectCast 。 (如果你想将一个已知types为System.Int32的值转换为VB.NET中System.Int64 types的值,你可以使用CLng ,而不是DirectCast 。)如果有一个types为System.Object的variables在那里, 那么使用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 ,在任何情况下使用它(即在编译时不知道对象的types)的情况下, 与直接()风格的转换相同在C#中


编辑 :好吧,耻辱我张贴一些VB代码,没有编译。 在重新考虑我所说的话之后,我回答第二个答案,但保持第一个答案。

如果你指的是使用DirectCast地方,你需要一个未知types的对象,并试图将其转换为所需的types,则它与C#的()casttypes相同:

VB:

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

C#:

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

这是因为,如果o被input为System.Object ,那么C#中的()操作将尝试解除它。 如果types不完全匹配,这将失败; 例如,如果o是一个盒装的System.Double ,那么(int)o将会抛出一个exception,因为o 必须作为System.Double被拆箱,然后才能被转换为System.Int32 (如果你不相信我,自己试试吧!)。


注意:以下内容不准确,因为DirectCast不执行扩展转换; 无论如何,我要把它留给子孙后代。

另一方面,在处理扩展和缩小转换时,正如你所指出的那样,在C#中使用()操作比简单地执行更多的工作(也就是说,你可以做(int)someDouble )。 在这种情况下, DirectCast相当于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; 

你可以自己实现它:

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

可用如下:

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

这个工作原理并不涉及用户定义的转换器,因为generics在运行时被“parsing”,但是在编译时parsing了types转换 – 框架实际上并不为每个T生成不同的实现,而是共享实现对于类似的T ,因此运行时没有解决自定义转换的信息。

实际上,如果编译器推断types化variables不能转换为其他types,编译器会捕获DirectCast违例

这些是实际的等值:

 double d = 10; int i = (int)d; Dim d As Double = 10 Dim i As Integer = d 

注意这个构造的危险性,当你仅仅在VB.NET中将double赋值为整数时,double将被意外地缩减为整数。

而C#程序员可以获得编译时安全性,而不会意外缩小variables.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) 

[编辑]

@丹涛:

在C#中不需要使用DirectCast,运行时也可以防止长整型值的加载。 这是csauve正在争论的是,C#没有DirectCast,DirectCast可以防止分配不同types的variables,而“因为”C#没有这个DirectCast,它将默默地分配不同types的错误。 但是正如你所看到的那样,情况并非如此,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#中,如果一个给定的关键字可以在另一个场景中使用(就像在这个variables的向下转换中一样),他们不会发明另外一个关键字来实现它。

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

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

在VB.NET中,如果你真的想要downcast这个variables,并且想用正交的方式去做,也就是只记住一个关键字,你必须这样做:

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

但是那不会编译,那么如何实现向下多变到整数? 你必须记住VB.NET的其他关键字。 而在C#中,它是正交的,你使用这个结构unboxvariables(typehere) ,你也downcast / (typehere)使用相同的结构(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的安全types转换行为,它们是一样的!

这个向下…

 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编程人员是通过意图进行编程,而不是在编程时昏昏欲睡,为什么在他完全意识到不能分配不同types的时候会使用DirectCast? 如果VB.NET程序员真正想要的是沮丧,他不应该首先尝试DirectCast。 现在,VB.NET程序员在发现DirectCast不能用于向下转换时,必须退格他写的东西,并用CInt(或CType)replace它,

你真的试图运行你的示例代码?

关于…

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

…你假定它会运行。 它也不会运行

让我试试这个。

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

 //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

如果它是正确的types,则抛出它,否则抛出一个InvalidCastException。

直投只能上升或下降一个分支,不能跨越一个不同的分支。

从这个解释中,它将直接等价于C#types。 但是在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#转换不会查找任何types转换器。 它只会查找任何已定义的显式/隐式操作符重载types,您正试图投。


VB的TryCast

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

我认为这种情况总结得最好,为什么DirectCast对非对象(对象关键字)types有编译时types检查安全性的错误感觉,并且只是为了后退。

 float f = 10; long l = f; Option Strict On Dim f As Single = 10 Dim l As Long = f 

AC#编码器,发现浮动不是直接分配到很长时间,将不会编译,将执行此操作:

 long l = (long)f; 

哪个是对的。

现在,让我们来看看我们的VB.NET编码器,一旦发现float不能分配到很长时间并且不会编译,将尝试这样做:

 Dim l As Long = DirectCast(f, Long) 

几秒钟之后…

VB.Net程序员:“请让我做我的招标,请编译,请… !!!”

之后的一些谷歌search和MSDN浏览的时刻:

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

 Dim l As Long = CLng(f) 

这就是我所说的DirectCast对编译时types检查安全性的错误感受。 如果程序员不知道何时何地应该使用DirectCast,那么他们的意思就是退后一步。 DirectCast是一种不会一直穿着的安全毯

在这种情况下DirectCast是多么有用,如果它终究不会被使用?


[编辑]

@Jules

我并不是说所有的VB.NET程序员都不知道DirectCast的真正用途是什么,他们中的一些人确实知道DirectCast只是用于对象types(以及在对象中装箱的基本types) 。

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#编译器不捕获不兼容的types赋值的印象,而VB.NET捕获它。 现在,为了这个明显的发现,将他的同事和一些论坛吹嘘VB.NET特性。

但是为了避免VB.NET程序员犯错误地推断第一个代码的意图。 上面的C#的代码片段开始了它的生活,就像这样写:

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

而这不会编译,C#编译器捕获不兼容的types分配,与同等的VB.NET与Option Strict On也不会编译(尽pipe只有当Option Strict设置为On ,太宽松时才会编译)。 所以我们需要使用(long)将types转换为long。 变成这样: long l = (long)f;

现在将一个variablestypes转换为另一个兼容types,就像我们转换这个代码一样…

 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 

但是,唉,这将不会编译,在兼容的基元types之间进行转换,这是DirectCast所缺乏的地方。它不提供任何对称于上面的C#代码,它不能用于投射兼容的基元types,尽pipe其名称直接演员

我看到它的方式,DirectCast应该被命名为CastObject ,因为它只能在对象types之间进行转换(也包括在对象中被装箱的原始types)。 DirectCast真的没有分配兼容的基元types(整数,双精度,以及它们的低和高对应)的业务。 当在兼容的原始types之间进行分配时,DirectCast不再有用,特别是你会退格,并用适当的代替它。

或者我看到它的另一种方式,DirectCast构造应该被修改,以便它可以像旧式和新式的语言一样,像C,C ++,C#,Java,Delphi,D等等一样来施放兼容的types。提供VB.NET对其他语言的显着对称性。 这样做,我们也可以扔掉(假设只是,我们不能让其他程序失败,依赖于旧function)所有的名称不直接映射到它的types(如CInt,CDbl,CSng等)的function,我们将只使用DirectCast来代替它们。

你有两种types的C#。 没有额外的代码,就没有C#中的DirectCast关键字的等价物。 你自己创build的最接近的是使用()

你有:

 My_Object c = (My_Object)object 

 My_Object c = object as My_Object 

在第一个,如果转换失败,它会抛出一个错误。 你在说:“我知道这个东西是什么,如果不是这样,那就错了。”

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

其他职位解释铸造:

显式和隐式types转换之间有什么区别?

()铸件应该是一样的; 它抛出一个InvalidCastException。 只要在C#中试试这个:

  string t = "hello"; object x = t; int j = (int) x;