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

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

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

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


当前回答

如果转换失败,'as'关键字不会抛出异常;它将变量设置为null(或为值类型的默认值)。

其他回答

如果您使用针对。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'

请忽略Jon Skeet的建议,re:避免测试-强制转换模式,即:

if (randomObject is TargetType)
{
    TargetType foo = randomObject as TargetType;
    // Do something with foo
}

认为这比强制转换和空测试花费更多的想法是错误的:

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

这是一种不起作用的微观优化。我运行了一些实际的测试,测试-强制转换实际上比强制转换-空比较更快,而且更安全,因为如果强制转换失败,则不可能在if之外的作用域中有空引用。

如果您想知道为什么测试-强制转换更快,或者至少不会更慢,有一个简单而复杂的原因。

简单:即使是简单的编译器也会将两个类似的操作(如test-and-cast)合并为一个测试和分支。强制转换-空测试可能强制执行两个测试和一个分支,一个用于类型测试和失败时转换为空,一个用于空检查本身。至少,它们都将优化为单个测试和分支,因此测试-强制转换既不会比强制转换-空测试慢也不会快。

复杂:为什么测试-强制转换更快:强制转换-空测试将另一个变量引入到外部作用域,编译器必须实时跟踪这个变量,并且它可能无法优化掉这个变量,这取决于你的控制流有多复杂。相反,“测试-强制转换”只在分隔的作用域内引入新变量,这样编译器就知道该变量在作用域退出后失效,从而更好地优化寄存器分配。

所以,请让这个“强制转换-空测试比测试-强制转换更好”的建议死掉吧。请。测试-强制转换既安全又快速。

as操作符只能用于引用类型,不能重载,如果操作失败,它将返回null。它永远不会抛出异常。

强制转换可以用于任何兼容的类型,它可以重载,如果操作失败,它将抛出异常。

使用哪一种取决于具体情况。首先,这是一个是否要对失败的转换抛出异常的问题。

as关键字的工作原理与兼容引用类型之间的显式强制转换相同,主要区别在于转换失败时它不会引发异常。相反,它在目标变量中产生一个空值。由于异常在性能方面非常昂贵,因此它被认为是一种更好的强制转换方法。

除了这里已经暴露的所有内容,我刚刚发现了一个我认为值得注意的实际差异,在显式选角之间

var x = (T) ...

相对于使用as操作符。

下面是例子:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GenericCaster<string>(12345));
        Console.WriteLine(GenericCaster<object>(new { a = 100, b = "string" }) ?? "null");
        Console.WriteLine(GenericCaster<double>(20.4));

        //prints:
        //12345
        //null
        //20.4

        Console.WriteLine(GenericCaster2<string>(12345));
        Console.WriteLine(GenericCaster2<object>(new { a = 100, b = "string" }) ?? "null");

        //will not compile -> 20.4 does not comply due to the type constraint "T : class"
        //Console.WriteLine(GenericCaster2<double>(20.4));
    }

    static T GenericCaster<T>(object value, T defaultValue = default(T))
    {
        T castedValue;
        try
        {
            castedValue = (T) Convert.ChangeType(value, typeof(T));
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }

    static T GenericCaster2<T>(object value, T defaultValue = default(T)) where T : class
    {
        T castedValue;
        try
        {
            castedValue = Convert.ChangeType(value, typeof(T)) as T;
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }
}

底线:GenericCaster2不能用于结构类型。GenericCaster意志。