C#相当于VB.NET的DirectCast?

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

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

我知道它有()强制转换和"as"关键字,但这些都符合ctype和trycast。

为了清楚起见,这些关键字做了以下的工作:

ctype/()强制转换:如果它已经是正确的类型,则强制转换它,否则查找类型转换器并调用它。如果找不到类型转换器,则引发InvalidcastException。

trycast/"as"关键字:如果类型正确,则强制转换,否则返回空值。

DirectCast:如果是正确的类型,则强制转换它,否则将引发InvalidCastException。

在我阐述了以上内容之后,一些人仍然回答说()是等价的,所以我将进一步阐述为什么这不是真的。

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

C-这编译并运行:

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

vb.net-这不编译

1
2
3
'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:

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


它看来,清澈的功能性,这是你想要的不是在C #。。。。。。。虽然这个吧………………… </P >

1
2
3
4
5
6
7
8
9
10
11
12
13
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呼叫它的类: </P >

1
2
3
4
5
6
7
8
9
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方法,它被提议基本上像DirectCast在vb.net中所做的那样。

1
2
3
4
5
6
7
8
9
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的观点不正确(至少我不知道)。
  • 它不必要地使用as(这就是为什么它首先有class约束);如果不起作用,调用(t)o将抛出InvalidCastException;为什么使用as检查值是否匹配,结果抛出的异常与使用(T)o路由开始时抛出的异常相同?
  • 该方法确实可以重写,以提供与DirectCast相同的结果,如下所示:

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

    有趣的观察:实际上,这个方法所要做的就是装箱一个值,然后尝试取消装箱。换句话说,DirectCast(12.0)实际上与(int)(object)12.0相同(两者都会抛出一个例外)。意识到这一点,提出的DirectCast方法完全没有必要。

    下面是一个例子,说明vb.net和c之间,DirectCast()的铸造是如何"不同"的:

    VB:

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

    C:

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

    好的,所以一个编译,另一个不编译。但是看看代码。当你已经知道一个对象的类型时,DirectCast有什么意义?这不是一个现实的比较,因为在vb.net中,没有任何理由像上面的代码那样调用DirectCast。(如果您想在vb.net中将已知的System.Int32类型的值转换为System.Int64类型的值,您可以使用CLng,而不是DirectCast。如果其中有一个类型为System.Object的变量,那么使用DirectCast是有意义的,并且下面的代码确实是等效的:

    VB:

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

    C:

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

    因此,我认为,在vb.net中,在任何实际使用它有意义的场景中(即,在编译时不知道对象类型时),DirectCast与c中的直()样式的强制转换相同。

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

    如果您所指的是DirectCast的用法,即取一个未知类型的对象并尝试将其强制转换为所需类型,那么它与c s()强制转换相同:

    VB:

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

    C:

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

    这是因为,如果o类型为System.Object类型,那么c中的()操作将尝试解除其绑定。如果类型不完全匹配,这将失败;例如,如果o是盒装System.Double,那么(int)o将抛出一个异常,因为o必须作为System.Double取消装箱,然后才能转换为System.Int32(如果您不相信我,请自己试试!).

    注意:下面的内容不准确,因为DirectCast不执行加宽转换;无论如何,我将把它留给后代。

    另一方面,在处理加宽和变窄转换时,使用c中的()操作比简单的铸造要做更多的工作,正如您所指出的(即,您可以执行(int)someDouble)。在这种情况下,DirectCast相当于c中的普通老任务:

    VB:

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

    C:

    1
    2
    int i = 12;
    long l = i;


    您可以自己实现它:

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

    可用性如下:

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

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


    实际上,如果编译器推断类型化变量无法转换为其他类型,则它只捕获DirectCast冲突。

    这些是实际等价物:

    1
    2
    3
    4
    5
    double d = 10;
    int i = (int)d;

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

    注意这个结构的危险性,当您在vb.net中只将double赋给integer时,double会意外地被缩减为integer。

    而C程序员得到的编译时安全性是不会意外地缩小变量.NET的大小。vb.net程序员必须始终将directcast作为一种安全的编程习惯。

    这些是实际等价物:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 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,运行时也会阻止从长到整的值的加载。这就是cSuve所主张的,c没有directcast,directcast可以阻止分配不同类型的变量,而"因为"c没有directcast,它会在分配不同类型时默默地出错。但正如你所看到的,情况并非如此,C的演员阵容与DirectCast完全相同。这将导致InvalidcastException运行时错误:

    1
    2
    3
    long l = 10;
    object o = l;
    int i = (int)o;

    这也将导致与上述相同的运行时错误:

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

    现在,"有趣"的部分就在这里出现了,用vb.net,你必须记住许多关键词才能完成一些事情。在C中,如果一个给定的关键字可以在另一个场景中使用(就像在这个变量的向下转换中一样),他们不会发明另一个关键字来实现它。

    在C中,您只需执行以下操作:

    1
    2
    3
    long l = 10;
    object o = l;
    int i = (int)(long)o;

    在vb.net中,如果您真的想降低变量的值,并想用正交的方法来实现它,即只记住一个关键字,则必须这样做:

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

    但这不会编译,那么如何实现长整型的下推?你必须记住vb.net的其他关键字。而在C中,它是正交的,使用这个构造(typehere)来解除变量的装箱,也使用相同的构造(typehere)来进行向下/向上的装箱。在vb.net中,从对象加载值和向下转换值之间存在一个基本的分离。所以在vb.net中,你必须这样做:

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

    隐马尔可夫模型。。我认为,cSuve混淆源于c多次使用(typehere),首先用于向下转换;第二,相同的构造(检查本帖的第一部分,object o = l)也用于从对象中拆出值,这可以确保它具有directcast的安全类型转换行为,它们是相同的!

    这是一个向下的投射…

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

    …不等于:

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

    如果您要执行向下强制转换,则必须执行以下操作:

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

    现在,如果一个vb.net程序员是故意编程的,而不是在编码时昏昏欲睡,为什么他会在充分意识到DirectCast不能分配不同类型时使用它呢?如果vb.net程序员真正想要的是向下投射,那么他不应该首先尝试DirectCast。现在,vb.net程序员在发现DirectCast不能用于downcast时,必须退格并用cint(或ctype)替换它。


    DirectCast()并不总是生成相同的IL,所以我认为这是vb和c编译器之间的区别。

    对于引用类型,使用castclassil指令进行强制转换,而对于值类型,编译器根据输入类型生成相关的il。

    在c中,从doubleinteger的转换发出conv.i4il指令,如果值太大,该指令将愉快地覆盖输出中的符号位或任何内容。在VB中,这是一个编译错误。

    有趣的是,如果使用一个中间的object变量来保存double,那么C和VB的强制转换都将失败…但在运行时。两个编译器都发出一条unbox指令,而不是试图进行转换。


    我认为这个场景最能说明为什么DirectCast对非对象(object关键字)类型的编译时类型检查安全性有错误的理解,并且只是想退格。好的。

    1
    2
    3
    4
    5
    6
    float f = 10;
    long l = f;

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

    当发现float不能直接分配给long且无法编译时,C编码人员将执行以下操作:好的。

    1
    long l = (long)f;

    这是正确的。好的。

    现在,让我们来看看我们的vb.net编码器,一旦发现float不能分配给long,也不能编译,我们将尝试这样做:好的。

    1
    Dim l As Long = DirectCast(f, Long)

    几秒钟后…好的。

    NET程序员:"请让我做我的出价,请编译,请…!!好的。

    在搜索fu和msdn之后的几分钟:好的。

    VB.NET程序员:"啊……所以我必须使用这个clng或ctype构造来转换变量。"好的。

    1
    Dim l As Long = CLng(f)

    这就是我所说的DirectCast对编译时类型检查安全性的错误理解。如果程序员不知道何时何地应该使用DirectCast,那么DirectCast就是用来退格的。DirectCast是一种不常穿的安全毯。好的。

    如果DirectCast最终不被使用,那么它在这个场景中有多有用?好的。

    [编辑]好的。

    @朱勒好的。

    我并不是说所有的vb.net程序员都不知道DirectCast的真正用途,他们中的一些人确实知道DirectCast只用于对象类型(以及装箱在对象中的基元类型)。好的。

    一种情况是,一个vb.net编码人员将现有的C代码重新编码到vb.net中,会得出错误的结论,即期望(无论正确与否)的语言彼此对称。好的。

    当他在代码中看到这个构造…好的。

    1
    TextBox txt = (TextBox)sender;

    …他会把这个翻译成:好的。

    1
    Dim txt As TextBox = DirectCast(sender, TextBox)

    这是正确的。好的。

    现在,因为我们程序员喜欢对称性,所以我们中的一些人(如果我不知道clng的话,我可能也是)会倾向于转换这段代码…好的。

    1
    2
    3
    4
    /* 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

    ……好的。

    1
    2
    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的代码片段开始了它的生命,就像这样最初是这样写的:好的。

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

    而这不会编译,C编译器捕获不兼容的类型分配,这与等效的vb.net与Option Strict On也不会编译(尽管仅当Option Strict设置为On时不会编译,太宽松)。所以我们需要使用(long)将float类型转换为long。变成这个:long l = (long)f;。好的。

    现在,为了将一个变量类型转换成另一个兼容的类型,我们用同样的方式转换这个代码…好的。

    1
    TextBox txt = (TextBox)sender;

    …到此代码:好的。

    1
    Dim txt As TextBox = DirectCast(sender, Textbox)

    我们必须转换此代码…好的。

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

    …到此代码:好的。

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

    但是,遗憾的是,在兼容的原始类型之间进行强制转换时,这并不能编译DirectCast。它没有为上面的C代码提供任何对称性,它不能用于转换兼容的基元类型,尽管它的名称是directcast。好的。

    在我看来,DirectCast应该命名为CastObject,因为它无论如何只能在对象类型(以及在对象中装箱的基元类型)之间进行转换。DirectCast实际上不需要分配兼容的基元类型(integer、double及其较低和较高的对应类型)。当在兼容的基元类型之间分配时,DirectCast不再有用,特别是您无论如何都要用退格键替换它,并用适当的替换它。好的。

    或者我看到的另一种方式,直接修改CdTcCasic结构,这样它就可以像旧的和新的语言一样兼容类型,例如C,C++,C语言,Java,Delphi,D等。这样做,它将提供VB.NET在其他类型的语言上的对称性。这样做,我们也可以放弃(假设只有这样,我们不能使其他依赖于旧函数的程序失败)所有名称不直接映射到其类型的函数(例如CINT、CDBL、CSNG等),我们只使用DirectCast来代替它们。好的。好啊。


    让我们试着给一次在这。 </P >

    第一,让我们这是清澈的。这将不会编译: </P >

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

    VB的CType

    在VB中使用,你会: </P >

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

    在C #,我会使用: </P >

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

    VB的directcast

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

    Direct cast can only go up or down a
    branch, never across to a different
    one.

    从解释说,它将是一种直接等价的C #铸造。然而,在C #你会只需要指定的铸造方法铸造式只读操作。铸造上像bluths是可选的。实例: </P >

    1
    2
    3
    4
    5
    6
    7
    // 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 #现并不看的任何类型的转换器。它是只读的查找表的任何显式/隐式定义的算子的超负荷的预测型你是试图做出的铸造的。 </P > VB的trycast

    你已经understood correctly说,这是相当于一个额外的C # AS关键字。 </P >


    你知道你真的很努力来运行你的代码样本吗? </P >

    对………………… </P >

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

    ...you posited说,它将运行。它也并不运行 </P >


    你有两种类型的演员在# C。没有额外的代码,有好的当量的directcast关键字在C #。。。。。。。"你有没有closest创造它自己是()使用。 </P >

    你有: </P >

    1
    My_Object c = (My_Object)object

    和 </P >

    1
    My_Object c = object as My_Object

    在第一次的一个,如果fails铸造,它throws是错误的。你是想说,"我知道这个面向的是,如果它是不在了,有一些错误的。" </P >

    在第二次,c指定的值是null(空的地方可能不能被分配的值的类型)。在这一个你是想说"我想我知道这是一个,但是如果不丢不安的错误,因为没有什么可能是错误的。" </P >

    其他铸造后的诠释: </P >

    什么是差分之间的显式和隐式casts??????? </P >


    (铸造的)应该是同样的;它throws安invalidcastexception。。。。。。。我尝试这在C #: </P >

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