gpt4 book ai didi

c# - 强制转换与在 CLR 中使用 'as' 关键字

转载 作者:IT王子 更新时间:2023-10-29 03:27:49 25 4
gpt4 key购买 nike

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

这两种转换方法有区别吗?如果是这样,是否存在成本差异或这如何影响我的计划?

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

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

最佳答案

线下的答案写于2008年。

C# 7 引入了模式匹配,它在很大程度上取代了 as运算符,你现在可以写:

if (randomObject is TargetType tt)
{
// Use tt here
}

请注意 tt在此之后仍在范围内,但未明确分配。 (它肯定是在 if 主体内赋值的。)在某些情况下这有点烦人,所以如果你真的关心在每个作用域中引入尽可能少的变量,你可能仍然想使用 is接着是类型转换。

我认为到目前为止(在开始这个答案时!)的任何答案都没有真正解释在哪里值得使用。
  • 不要这样做:
    // Bad code - checks type twice for no reason
    if (randomObject is TargetType)
    {
    TargetType foo = (TargetType) randomObject;
    // Do something with foo
    }

    这不仅检查两次,而且可能检查不同的东西,如果 randomObject是一个字段而不是一个局部变量。如果另一个线程更改了 randomObject 的值,则“if”可能会通过但随后转换会失败。两者之间。
  • randomObject真的应该是 TargetType 的一个实例,即如果不是,则意味着存在错误,然后强制转换是正确的解决方案。这会立即引发异常,这意味着在不正确的假设下不再进行任何工作,并且异常正确地显示了错误的类型。
    // 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是引用类型,然后使用这样的代码:
    TargetType convertedRandomObject = randomObject as TargetType;
    if (convertedRandomObject != null)
    {
    // Do stuff with convertedRandomObject
    }
  • randomObject可能是 TargetType 的一个实例和 TargetType是值类型,那么我们不能使用 asTargetType本身,但我们可以使用可空类型:
    TargetType? convertedRandomObject = randomObject as TargetType?;
    if (convertedRandomObject != null)
    {
    // Do stuff with convertedRandomObject.Value
    }

    (注意:目前这是 actually slower than is + cast 。我认为它更优雅和一致,但我们走了。)
  • 如果你真的不需要转换后的值,而只需要知道它是否是TargetType的实例,那么is接线员是你的 friend 。在这种情况下,TargetType 是引用类型还是值类型并不重要。
  • 可能还有其他涉及泛型的情况,其中 is很有用(因为你可能不知道 T 是否是引用类型,所以你不能使用 as)但它们相对模糊。
  • 我几乎肯定用过 is对于之前的值类型情况,没有考虑使用可空类型和 as一起:)


  • 编辑:请注意,除了值类型的情况外,以上都没有谈到性能,在那里我注意到拆箱为可空值类型实际上更慢 - 但一致。

    根据 naasking 的回答,is-and-cast 或 is-and-as 都与现代 JIT 的 as-and-null-check 一样快,如下面的代码所示:
    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);
    }
    }

    在我的笔记本电脑上,这些都在大约 60 毫秒内执行。有两点需要注意:
  • 它们之间没有显着差异。 (实际上,在某些情况下,as-plus-null-check 肯定会更慢。上面的代码实际上使类型检查变得容易,因为它是针对密封类的;如果您正在检查接口(interface),则平衡会稍微提示赞成 as-plus-null-check。)
  • 他们都快疯了。这根本不会成为您代码中的瓶颈,除非您之后真的不打算对这些值做任何事情。

  • 所以我们不用担心性能。让我们担心正确性和一致性。

    我认为 is-and-cast(或 is-and-as)在处理变量时都是不安全的,因为它引用的值的类型可能会由于测试和强制转换之间的另一个线程而改变。这将是一种非常罕见的情况 - 但我宁愿有一个我可以一致使用的约定。

    我还认为 as-then-null-check 可以更好地分离关注点。我们有一个尝试转换的语句,然后是一个使用结果的语句。 is-and-cast 或 is-and-as 执行测试,然后再次尝试转换值。

    换句话说,有人会写:
    int value;
    if (int.TryParse(text, out value))
    {
    value = int.Parse(text);
    // Use value
    }

    这就是 is-and-cast 正在做的事情——尽管显然是以一种相当便宜的方式。

    关于c# - 强制转换与在 CLR 中使用 'as' 关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/496096/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com