使用Cast两次,或者使用一次并创建一个新变量

时间:2010-09-22 11:45:39

标签: c# .net

在今天的上一个问题中,这两种不同的方法被作为答案提出问题。

我们有一个可能会或可能不会实现IDisposable的对象。如果是的话,我们想要处理它,如果不是我们什么也不做。这两种不同的方法是:

1)

if(toDispose is IDisposable)
  (toDispose as IDisposable).Dispose();

2)

IDisposable disposable = toDispose as IDisposable;
if( disposable != null )
  disposable.Dispose();

主要是,从评论中可以看出,共识是2)是最好的方法。

但是看看差异,我们归结为:

1)在toDispose上执行两次演员。

2)仅执行一次转换,但创建一个新的中间对象。

我猜测2会慢一点因为它必须分配一个新的局部变量,所以为什么这被认为是这种情况下的最佳解决方案?这完全是因为可读性问题?

6 个答案:

答案 0 :(得分:13)

没有真正回答你的问题,但我建议你这个结构:

using (toDispose as IDisposable)
{
    ...
}

让编译器担心ifsfinallyDispose来电。

答案 1 :(得分:12)

关于施法的经验法则:

  • 如果 值为正确类型的错误/错误,只需投出
  • 否则请使用as,就像第二种情况一样
  • 如果您正在处理值类型,则可以将as与可空类型一起使用(为了保持一致性),或者使用is和直接投射

请注意,您的第二个表单不会创建“新的中间对象”。它创建了一个新的中间变量。那么你的第一种方法是否真的 - 只是变量被编译器有效地隐藏了。它仍然作为堆栈位置存在于IL中,但它在源代码中没有任何表示。

说完所有这些,在这个特殊情况下(你只想处理),Darin的方法是最好的,我相信。

答案 2 :(得分:4)

它被认为是一种更好的解决方案,因为变量分配被认为比强制转换更快。此外,演员可以通过编译器对其进行优化。

无论哪种方式,无论如何这都是微优化的。 使用您认为最容易维护的代码。

答案 3 :(得分:2)

第二种选择实际上有点快。进行额外演员需要花费更多时间而不是访问本地变速器。

分配局部变量并不慢。实际上它根本没有时间。

当输入方法时,通过向下移动堆栈指针来创建堆栈帧,以便为方法中的本地数据分配空间。从堆栈指针中减去更大的数字不需要更长的时间,因此根本不需要时间为局部变量分配空间。这几乎没有时间,但实际上是零时间。

局部变量的唯一成本是你正在使用堆栈空间,但由于它只有一兆字节(IIRC)堆栈中的几个字节,所以除非你正在进行深度递归调用,否则没有问题。

此外,如果需要,编译器可以自己创建局部变量,因此两种方法最终都可能最终使用局部变量。

答案 4 :(得分:1)

与使用as

相比,使用反射是否会在这里工作还是会变慢?

我创建了两个类,一个名为ICanDispose,实现了IDisposable,另一个名为ICanNotDispose,未实现IDisposable

在我的ICanDispose课程中,我只是显示一个消息框,以检查反射实际上是否调用了Dispose方法。

我的表单上有一个按钮,执行下面的代码。使用反射它会检查我的对象是否实现IDisposable接口,如果是,则调用Dispose方法。

private void button1_Click(object sender, EventArgs e)
{
    ICanDispose myObject1 = new ICanDispose();
    ICanNotDispose myObject2 = new ICanNotDispose();

    // Checking object 1 which does implement IDisposable.
    if (myObject1.GetType().GetInterface("IDisposable", true) != null)
    {
        myObject1.GetType().InvokeMember(
            "Dispose", 
            System.Reflection.BindingFlags.Default | System.Reflection.BindingFlags.InvokeMethod, 
            null, 
            Activator.CreateInstance(myObject1.GetType()), 
            null);
    }

    // Checking object 2 which does not implement IDisposable.    
    if (myObject2.GetType().GetInterface("IDisposable", true) != null)
    {
        myObject2.GetType().InvokeMember(
            "Dispose", 
            System.Reflection.BindingFlags.Default | System.Reflection.BindingFlags.InvokeMethod, 
            null, 
            Activator.CreateInstance(myObject2.GetType()), 
            null);
    }
}

答案 5 :(得分:1)

此处没有人提到FxCop在第一次approch时显示DoNotCastUnnecessarily警告。对此规则的帮助表明第二种方法取代了第一种方法

http://msdn.microsoft.com/en-us/library/ms182271(VS.90).aspx

  

重复演员表会降低演奏效果,   特别是当演员表演时   在紧凑的迭代中执行   声明。对于显式重复   转换操作,存储结果   转换为局部变量并使用   局部变量而不是   重复演员。

     

如果C#是运算符用于测试   演员是否会成功   考虑到实际演员阵容   测试as运算符的结果   代替。这提供了相同的   没有隐含的功能   施法操作是由   操作