26

我定义了以下结构:

public struct Call
{
    public SourceFile caller;
    public SourceFile callee;

    public Call(SourceFile caller, SourceFile callee)
    {
        this.caller = caller;
        this.callee = callee;
    }
}

后来,我将它分配给另一个对象的 Tag 属性:

line.Tag = new Call(sf1, sf2);

但是当我尝试像这样检索 Tag 属性时,

Call call = line.Tag as Call;

Visual Studio 给出以下编译时错误:

运算符 as 必须在引用类型或可为空的类型中使用

那是什么意思?我该如何解决?

4

6 回答 6

36

一些现有的答案并不完全正确。您不能将不可为空的类型与 一起使用as,因为as如果第一个操作数实际上不是适当的类型,则结果是该类型的空值。

但是,您可以使用as值类型...如果它们可以为空:

int a = 10;
object o = a;

int? x = o as int?; // x is a Nullable<int> with value 10
long? y = o as long?; // y is a Nullable<long> with the null value

所以你可以使用:

Call? call = line.Tag as Call?;

然后您可以将其用作:

if (call != null)
{
    // Do stuff with call.Value
}

不过有两个警告:

  • 以我的经验,这比仅使用is后跟演员要慢
  • 您应该认真重新考虑您当前的Call类型:
    • 它暴露了公共领域,这通常是糟糕的封装
    • 它是一个可变值类型,这几乎可以肯定是一个错误

我强烈建议你把它改成一个类 - 无论如何这个问题都会消失。

另一个想法:如果标签应该始终是 a Call,那么最好转换它:

Call call = (Call) line.Tag;

这样,如果数据不符合您的期望(即存在一些错误,例如Tag不是 a Call),那么您可以及早发现它,而不是在您可能完成一些其他工作之后。请注意,此强制转换的行为将根据Call是结构还是类而有所不同,如果Tag为 null - 您可以将 null 值强制转换为引用类型(或可空值类型)的变量,但不能强制转换为不可空值类型。

于 2010-12-09T17:46:02.077 回答
34

结构是值类型,因此不能与as运算符一起使用。如果强制转换失败,as操作员必须能够分配 null 值。这仅适用于引用类型或可为空的值类型。

有几种方法可以解决这个问题,但最好的办法是将Call类型从结构更改为类。这实际上会将您的类型从值类型更改为引用类型,这允许as操作员在强制转换失败时分配 null 值。

有关值类型与引用类型的更多信息,是一篇不错的文章。另外,看看 MSDN:

于 2010-12-09T17:42:58.433 回答
12

来自 C# 规范

§7.10.11 as 运算符用于将值显式转换为给定的 引用类型可为空的类型。与强制转换表达式(第 7.7.6 节)不同,as 运算符从不抛出异常。相反,如果指示的转换不可行,则结果值为null

引用和可为空的类型可以为空。结构是值类型,因此它们不能为空。

于 2010-12-09T17:46:26.707 回答
1
Call? call = line.Tag as Call?;
于 2010-12-09T17:45:59.807 回答
0

这是 C# 的限制。如果类型是引用类型,那么如果转换失败,它只会返回“null”,但由于它是值类型,它不知道转换失败时返回什么。

您必须将 as 的使用替换为两个:'is' 和 'as'

if (line.Tag is Call) {
  call = (Call)line.Tag;
} else {
  // Do whatever you would do if as returned null.
}
于 2010-12-09T17:43:50.953 回答
-1

含义是什么 - 如前所述,结构是值类型。

我该如何解决它 - 将其更改为

Call call = line.Tag;
于 2010-12-09T17:46:08.333 回答