在编程接口时,我发现我做了很多强制转换或对象类型转换。

这两种转换方法有什么区别吗?如果是的话,是否有成本差异,或者这对我的程序有什么影响?

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);
    }
}

另外,“一般来说”首选的方法是什么?


当前回答

看看这些链接:

http://gen5.info/q/2008/06/13/prefix-casting-versus-as-casting-in-c/ http://www.codeproject.com/Articles/8052/Type-casting-impact-over-execution-performance-in

它们向您展示了一些细节和性能测试。

其他回答

两者之间一个更微妙的区别是,当涉及到强制转换操作符时,"as"关键字不能用于强制转换:

public class Foo
{
    public string Value;

    public static explicit operator string(Foo f)
    {
        return f.Value;
    }

}

public class Example
{
    public void Convert()
    {
        var f = new Foo();
        f.Value = "abc";

        string cast = (string)f;
        string tryCast = f as string;
    }
}

这将不会在最后一行进行编译(尽管我认为在以前的版本中是这样),因为“as”关键字不考虑强制转换操作符。line string cast = (string)f;不过效果还不错。

如果不能执行返回null的转换,As永远不会抛出异常(As仅对引用类型操作)。所以使用as基本上相当于

_myCls2 = _myObj is MyClass ? (MyClass)_myObj : null;

另一方面,c风格的强制转换在无法进行转换时抛出异常。

这并不能回答你的问题,但我认为这是一个重要的相关点。

如果你正在为一个接口编程,你不应该需要强制转换。希望这种类型的演员很少。如果不是,您可能需要重新考虑一些接口。

这是另一个答案,带有一些IL比较。考虑这个类:

public class MyClass
{
    public static void Main()
    {
        // Call the 2 methods
    }

    public void DirectCast(Object obj)
    {
        if ( obj is MyClass)
        { 
            MyClass myclass = (MyClass) obj; 
            Console.WriteLine(obj);
        } 
    } 


    public void UsesAs(object obj) 
    { 
        MyClass myclass = obj as MyClass; 
        if (myclass != null) 
        { 
            Console.WriteLine(obj);
        } 
    }
}

现在看看每种方法产生的IL。即使操作码对您没有任何意义,您也可以看到一个主要的区别-在DirectCast方法中,isinst被调用后是castclass。所以基本上是两次调用而不是一次。

.method public hidebysig instance void  DirectCast(object obj) cil managed
{
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.1
  IL_0009:  castclass  MyClass
  IL_000e:  pop
  IL_000f:  ldarg.1
  IL_0010:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0015:  ret
} // end of method MyClass::DirectCast

.method public hidebysig instance void  UsesAs(object obj) cil managed
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (class MyClass V_0)
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  brfalse.s  IL_0010
  IL_000a:  ldarg.1
  IL_000b:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0010:  ret
} // end of method MyClass::UsesAs

isinst关键字与castclass的对比

这篇博文对这两种方法进行了比较。他的总结是:

在直接比较中,isinst比castclass快(尽管只有一点点) 当必须执行检查以确保转换成功时,isinst明显比castclass快 不应该使用isinst和castclass的组合,因为这比最快的“安全”转换慢得多(慢12%以上)

我个人总是使用a,因为它易于阅读,并且是。net开发团队(或者Jeffrey Richter)推荐的。

如果您使用针对。net Framework 4的Office PIAs。X你应该使用as关键字,否则它将无法编译。

Microsoft.Office.Interop.Outlook.Application o = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem m = o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem) as Microsoft.Office.Interop.Outlook.MailItem;

当目标是。net 2.0时,强制转换是可以的:

Microsoft.Office.Interop.Outlook.MailItem m = (Microsoft.Office.Interop.Outlook.MailItem)o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);

当目标是。net 4时。X的误差为:

缺少编译器需要的成员'Microsoft.CSharp.RuntimeBinder.Binder.Convert'

缺少编译器需要的成员'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'