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

发布于 2024-10-06 17:28:04 字数 550 浏览 8 评论 0原文

我定义了以下结构:

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 必须在 a 中使用 引用类型或可为空类型

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

I defined the following struct:

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

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

Later, I assign it to the Tag property of another object:

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

But when I try to retrieve the Tag property like so,

Call call = line.Tag as Call;

Visual Studio gives the following compile-time error:

The operator as must be used within a
reference type or nullable type

What is the meaning of that? And how can I solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

时光瘦了 2024-10-13 17:28:05

一些现有的答案不太正确。您不能将不可空类型与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 类型:
    • 它暴露了公共字段,这通常是封装很差的
    • 这是一个可变值类型,这几乎肯定是一个错误

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

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

Call call = (Call) line.Tag;

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

Some of the existing answers aren't quite right. You can't use non-nullable types with as, because the result of as is the null value of the type if the first operand isn't actually of an appropriate type.

However, you can use as with value types... if they're nullable:

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

So you could use:

Call? call = line.Tag as Call?;

Then you can use it as:

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

Two caveats though:

  • In my experience this is slower than just using is followed by a cast
  • You should seriously reconsider your current Call type:
    • It's exposing public fields, which is generally poor encapsulation
    • It's a mutable value type, which is almost certainly a mistake

I would strongly suggest you make it a class instead - at which point this problem goes away anyway.

Another thought: if the tag should always be a Call, then it's better to cast it:

Call call = (Call) line.Tag;

That way, if the data doesn't match your expectation (i.e. there's some bug such that the Tag isn't a Call) then you get to find out about it early, rather than after you've potentially done some other work. Note that this cast will behave differently depending on whether Call is a struct or a class, if Tag is null - you can cast a null value to a variable of a reference type (or a nullable value type), but not to a non-nullable value type.

独闯女儿国 2024-10-13 17:28:05

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

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

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

A struct is a value type, so it cannot be used with the as operator. The as operator must be able to assign a value of null if the cast fails. This is only possible with a reference type or a nullable value type.

There are a couple ways to solve this, but your best bet is to change your Call type from a struct to a class. This will essentially change your type from a value type to a reference type, which allows the as operator to assign a value of null if the cast fails.

For more information on value types vs. reference types, this is a decent article. Also, have a look on MSDN:

粉红×色少女 2024-10-13 17:28:05

来自 C# 规范

§7.10.11 as 运算符用于
显式地将值转换为给定值
引用类型可空类型。与强制转换表达式不同
(§7.7.6),as 运算符永远不会抛出异常
一个例外。相反,如果
表明转换是不可能的,
结果值为null

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

From the C# Spec

§7.10.11 The as operator is used to
explicitly convert a value to a given
reference type or nullable type. Unlike a cast expression
(§7.7.6), the as operator never throws
an exception. Instead, if the
indicated conversion is not possible,
the resulting value is null.

References and nullable types can be null. Stucts are value types so they can't be null.

心如荒岛 2024-10-13 17:28:05
Call? call = line.Tag as Call?;
Call? call = line.Tag as Call?;
夏日落 2024-10-13 17:28:05

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

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

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

It's a limitation of C#. If the type were a reference type, then if the cast failed it would simply return 'null', but since it's a value type, it doesn't know what to return when the cast fails.

You must replace your use of as with two: 'is' and 'as'

if (line.Tag is Call) {
  call = (Call)line.Tag;
} else {
  // Do whatever you would do if as returned null.
}
凉墨 2024-10-13 17:28:05

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

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

Call call = line.Tag;

What is the meaning - As stated, structures are value types.

How can I solve it - Change it to

Call call = line.Tag;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文