Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以';我不能对结构使用as关键字吗?_C#_.net_Casting_Type Systems_As Operator - Fatal编程技术网

C# 为什么可以';我不能对结构使用as关键字吗?

C# 为什么可以';我不能对结构使用as关键字吗?,c#,.net,casting,type-systems,as-operator,C#,.net,Casting,Type Systems,As Operator,我定义了以下结构: public struct Call { public SourceFile caller; public SourceFile callee; public Call(SourceFile caller, SourceFile callee) { this.caller = caller; this.callee = callee; } } 稍后,我将其指定给另一个对象的Tag属性: line.Ta

我定义了以下结构:

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


这是什么意思?如何解决它呢?

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

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

有关值类型与引用类型的更多信息,请参阅本文。另外,请查看MSDN:

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

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

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

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

      但是,您可以将
      作为
      与值类型一起使用。。。如果它们可以为空:

      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
      
      然后您可以将其用作:

      if (call != null)
      {
          // Do stuff with call.Value
      }
      
      但有两个警告:

      • 根据我的经验,这比只使用
        is
        然后使用cast要慢
      • 您应该认真重新考虑您当前的
        通话类型:
        
        • 它公开了公共字段,这通常是很差的封装
        • 这是一种可变值类型,几乎可以肯定是一个错误
      我强烈建议你将它改为一个类,在这一点上,这个问题无论如何都会消失

      另一个想法是:如果标记应该始终是
      调用
      ,那么最好将其强制转换为:

      Call call = (Call) line.Tag;
      

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

      这是什么意思?如上所述,结构是值类型

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

      Call call = line.Tag;
      
      从C#Spec

      §7.10.11 as操作员用于 将值显式转换为给定值 引用类型可为空类型。不像演员的表情 (§7.7.6),as操作员从不抛出 例外。相反,如果 指示的转换是不可能的, 结果值为null


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

      如果强制转换失败,则不能分配null是关键+1你为什么要把它做成一个结构?可变结构是个坏主意。@Mark:+1并且该结构将被装箱存储在标记属性中……嗯,它不必是可变的。但我认为我应该为我们提供一个更好的类,我不会把它称为C#的“限制”——这听起来像是应该修正的东西。这是一个自然的限制,基于“as”操作符的意图。还有其他有效的设计点。如果x不能显式地转换为T,C#1.0可能会使表达式'x as T'返回默认值(T)。随着可空类型的引入,C#可能会使'x as T'的返回类型在T是值类型时可以为空(我还应该说,考虑到新程序员对as on值类型的错误次数,“限制”在我看来,这是一个准确的描述。)
      Call call = (Call) line.Tag;
      
      Call call = line.Tag;