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中DirectCast
function。
static T DirectCast<T>(object o) where T : class { T value = o as T; if (value == null && o != null) { throw new InvalidCastException(); } return value; }
以上是上述方法的问题:
- 它有一个
where T : class
约束,而DirectCast
不能。 - 它把它的参数作为一个
System.Object
– 再次,不是DirectCast
(至less不是我所知道的)。 - 它不必要地使用(这就是为什么它首先有
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;