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

23 .net c# type-systems casting as-operator

我定义了以下结构:

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

    public Call(SourceFile caller, SourceFile callee)
    {
        this.caller = caller;
        this.callee = callee;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

line.Tag = new Call(sf1, sf2);
Run Code Online (Sandbox Code Playgroud)

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

Call call = line.Tag as Call;
Run Code Online (Sandbox Code Playgroud)

Visual Studio提供以下编译时错误:

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

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

Jon*_*eet 34

一些现有的答案并不完全正确.您不能使用非可空类型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
Run Code Online (Sandbox Code Playgroud)

所以你可以使用:

Call? call = line.Tag as Call?;
Run Code Online (Sandbox Code Playgroud)

然后你可以用它作为:

if (call != null)
{
    // Do stuff with call.Value
}
Run Code Online (Sandbox Code Playgroud)

但有两点需要注意:

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

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

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

Call call = (Call) line.Tag;
Run Code Online (Sandbox Code Playgroud)

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


Jas*_*own 33

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

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

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


Con*_*rix 12

来自C#规范

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

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