铸造VS使用'为'在CLR关键字 [英] Casting vs using the 'as' keyword in the CLR

查看:136
本文介绍了铸造VS使用'为'在CLR关键字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当编程接口,我发现我做了很多铸造或对象类型的转换。

When programming interfaces, I've found I'm doing a lot of casting or object type conversion.

有没有转换这两种方法之间的差异?如果是这样,是有成本差异或如何影响我的程序?

Is there a difference between these two methods of conversion? If so, is there a cost difference or how does this affect my program?

public interface IMyInterface
{
    void AMethod();
}

public class MyClass : IMyInterface
{
    public void AMethod()
    {
       //Do work
    }

    // Other helper methods....
}

public class Implementation
{
    IMyInterface _MyObj;
    MyClass _myCls1;
    MyClass _myCls2;

    public Implementation()
    {
        _MyObj = new MyClass();

        // What is the difference here:
        _myCls1 = (MyClass)_MyObj;
        _myCls2 = (_MyObj as MyClass);
    }
}

此外,什么是一般的preferred方法?

Also, what is "in general" the preferred method?

推荐答案

我不认为任何的答案到目前为止(在开始这个答案的!时间)真的解释它是值得使用的。

I don't think any of the answers so far (at the time of starting this answer!) have really explained where it's worth using which.


  • 不这样做:

  • Don't do this:

// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
    TargetType foo = (TargetType) randomObject;
    // Do something with foo
}

这不仅检查两次,但也可以检查不同的东西,如果 randomObject 是一个字段,而不是局部变量。这是可能的如果通过,但随后中投失败,如果另一个线程更改 randomObject 的值介于两者之间。

Not only is this checking twice, but it may be checking different things, if randomObject is a field rather than a local variable. It's possible for the "if" to pass but then the cast to fail, if another thread changes the value of randomObject between the two.

如果 randomObject 真的的是的TargetType 的一个实例,即如果它不是,这意味着有一个bug,然后铸造是正确的解决方案。这立即引发异常,这意味着没有更多的工作是根据不正确的假设做,异常正确地显示错误的类型。

If randomObject really should be an instance of TargetType, i.e. if it's not, that means there's a bug, then casting is the right solution. That throws an exception immediately, which means that no more work is done under incorrect assumptions, and the exception correctly shows the type of bug.

// This will throw an exception if randomObject is non-null and
// refers to an object of an incompatible type. The cast is
// the best code if that's the behaviour you want.
TargetType convertedRandomObject = (TargetType) randomObject;


  • 如果 randomObject 可能的是的TargetType 的一个实例,的TargetType 是引用类型,然后使用code是这样的:

  • If randomObject might be an instance of TargetType and TargetType is a reference type, then use code like this:

    TargetType convertedRandomObject = randomObject as TargetType;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject
    }
    


  • 如果 randomObject 可能的是的TargetType 的一个实例,的TargetType 是值类型,那么我们就不能使用的TargetType 本身,但我们可以用一个可空类型:

  • If randomObject might be an instance of TargetType and TargetType is a value type, then we can't use as with TargetType itself, but we can use a nullable type:

    TargetType? convertedRandomObject = randomObject as TargetType?;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject.Value
    }
    

    (注:目前这是<一个href=\"http://stackoverflow.com/questions/1583050/performance-surprise-with-as-and-nullable-types\">actually比+投慢。我认为这是更优雅和一致的,但我们走。)

    (Note: currently this is actually slower than is + cast. I think it's more elegant and consistent, but there we go.)

    如果你真的不需要转换的值,但是你只需要知道它是否的的TargetType的实例,那么运营商是你的朋友。在这种情况下,它无关紧要的TargetType是否是引用类型或值类型。

    If you really don't need the converted value, but you just need to know whether it is an instance of TargetType, then the is operator is your friend. In this case it doesn't matter whether TargetType is a reference type or a value type.

    有可能会涉及仿制药的其他情况下是非常有用的(因为你可能不知道T是否是引用类型或没有,所以你不能如使用),但他们是相对模糊的。

    There may be other cases involving generics where is is useful (because you may not know whether T is a reference type or not, so you can't use as) but they're relatively obscure.

    我几乎可以肯定,使用的值类型的情况下,现在前,没有使用可空类型的思想和作为在一起:)

    I've almost certainly used is for the value type case before now, not having thought of using a nullable type and as together :)

    编辑:请注意,没有对性能上面的会谈,除了值类型的情况下,在那里我已经指出,拆箱到一个空值类型的实际上是慢 - 但一致的。

    Note that none of the above talks about performance, other than the value type case, where I've noted that unboxing to a nullable value type is actually slower - but consistent.

    作为每naasking的答案,是和 - 铸造或是和 - 作为都是一样快和空检查与现代即时编译器,如由下面的code:

    As per naasking's answer, is-and-cast or is-and-as are both as fast as as-and-null-check with modern JITs, as shown by the code below:

    using System;
    using System.Diagnostics;
    using System.Linq;
    
    class Test
    {
        const int Size = 30000000;
    
        static void Main()
        {
            object[] values = new object[Size];
            for (int i = 0; i < Size - 2; i += 3)
            {
                values[i] = null;
                values[i + 1] = "x";
                values[i + 2] = new object();
            }
            FindLengthWithIsAndCast(values);
            FindLengthWithIsAndAs(values);
            FindLengthWithAsAndNullCheck(values);
        }
    
        static void FindLengthWithIsAndCast(object[] values)        
        {
            Stopwatch sw = Stopwatch.StartNew();
            int len = 0;
            foreach (object o in values)
            {
                if (o is string)
                {
                    string a = (string) o;
                    len += a.Length;
                }
            }
            sw.Stop();
            Console.WriteLine("Is and Cast: {0} : {1}", len,
                              (long)sw.ElapsedMilliseconds);
        }
    
        static void FindLengthWithIsAndAs(object[] values)        
        {
            Stopwatch sw = Stopwatch.StartNew();
            int len = 0;
            foreach (object o in values)
            {
                if (o is string)
                {
                    string a = o as string;
                    len += a.Length;
                }
            }
            sw.Stop();
            Console.WriteLine("Is and As: {0} : {1}", len,
                              (long)sw.ElapsedMilliseconds);
        }
    
        static void FindLengthWithAsAndNullCheck(object[] values)        
        {
            Stopwatch sw = Stopwatch.StartNew();
            int len = 0;
            foreach (object o in values)
            {
                string a = o as string;
                if (a != null)
                {
                    len += a.Length;
                }
            }
            sw.Stop();
            Console.WriteLine("As and null check: {0} : {1}", len,
                              (long)sw.ElapsedMilliseconds);
        }
    }
    

    在我的笔记本电脑,这些都约60ms的执行英寸有两点需要注意:

    On my laptop, these all execute in about 60ms. Two things to note:


    • 有它们之间没有显著差异。 (事实上​​,在有些情况下其作为加空支票绝对的的慢以上code实际上使得类型检查容易的,因为它是一个密封类;如果你重新检查接口,平衡尖端略倾向于为加空检查。)

    • 他们都的疯狂的快。这仅仅不会的在你的code中的瓶颈,除非你真的是不会做的任何的与事后的值。

    • There's no significant difference between them. (In fact, there are situations in which the as-plus-null-check definitely is slower. The above code actually makes the type check easy because it's for a sealed class; if you're checking for an interface, the balance tips slightly in favour of as-plus-null-check.)
    • They're all insanely fast. This simply will not be the bottleneck in your code unless you really aren't going to do anything with the values afterwards.

    因此​​,让我们不用担心性能。让我们担心的正确性和一致性。

    So let's not worry about the performance. Let's worry about correctness and consistency.

    我认为是和播送(或者是和 - 如)与变量处理时都是不安全的,作为值的类型是指由于测试和模具之间另一个线程可能会改变。这将是一个pretty罕见的情况 - 但是我宁愿有一个约定,我可以一直使用

    I maintain that is-and-cast (or is-and-as) are both unsafe when dealing with variables, as the type of the value it refers to may change due to another thread between the test and the cast. That would be a pretty rare situation - but I'd rather have a convention which I can use consistently.

    我也坚持认为,AS-然后空检查给出的担忧较好的分离。我们有一个说法,它试图转换,再一个它使用的结果声明。该是和铸造或IS-和为执行测试和然后的另一种尝试将该值转换。

    I also maintain that the as-then-null-check gives a better separation of concerns. We have one statement which attempts a conversion, and then one statement which uses the result. The is-and-cast or is-and-as performs a test and then another attempt to convert the value.

    要换个说法,会有人的曾经的写:

    To put it another way, would anyone ever write:

    int value;
    if (int.TryParse(text, out value))
    {
        value = int.Parse(text);
        // Use value
    }
    

    这就是那种什么和铸造是做 - 虽然很明显在一个相当便宜的方式。

    That's sort of what is-and-cast is doing - although obviously in a rather cheaper way.

    这篇关于铸造VS使用'为'在CLR关键字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆