为什么我不能在结构中使用as关键字?

我定义了以下结构:

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提供以下编译时错误:

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

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

struct是值类型,因此不能与as运算符一起使用。 如果转换失败, as运算符必须能够赋值null。 这仅适用于引用类型或可空值类型。

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

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

  • 价值类型
  • 参考类型
  • 作为运营商
  • 可空类型 。

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

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

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

所以你可以使用:

 Call? call = line.Tag as Call?; 

然后你可以用它作为:

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

但有两点需要注意:

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

我强烈建议你把它变成一个class级 – 无论如何这个问题都会消失。

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

 Call call = (Call) line.Tag; 

这样,如果数据与您的期望不符(即有一些错误,使得Tag不是Call ),那么您可以尽早找到它,而不是在您可能完成其他工作之后。 请注意,根据Call是一个结构还是一个类,如果Tag为null,这个转换将表现不同 – 您可以将null值转换为引用类型的变量(或可空值类型),但不能转换为非可空值类型。

来自C#规范

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

引用和可空类型可以为null。 Stucts是值类型,因此它们不能为null。

 Call? call = line.Tag as Call?; 

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

您必须将以下两种用法替换为:’is’和’as’

 if (line.Tag is Call) { call = (Call)line.Tag; } else { // Do whatever you would do if as returned null. } 

意义是什么 – 如上所述,结构是价值类型。

我怎样才能解决它 – 改成它

 Call call = line.Tag;