为什么C#不允许静态结构体?

9

我曾经认为结构体是一种次要的东西,或者有较少的功能。也许是因为面向对象编程(OOP)概念将所有的东西都强制转换成类。

从我对 C# 的了解中,我知道将一个类设置为 static,可以确保它的所有成员和函数都是静态的。此外,由于只存在一个实例,我们不能有构造函数来初始化该类。

public static struct mystruct
{
    public static int a;
}

我在Stack Overflow上被指出这是一种错误的方法。有人可以详细解释一下吗?

当我创建一个新的cs文件并在控制台中编译它时,我得到了适当的错误提示“static is not valid for this item”。但奇怪的是,当我将它添加到一个现有的工作项目中以查看编译器是否会抱怨时,令我惊讶的是它没有。这是为什么呢?


6
在C#中,static在类型声明上是abstract sealed的别名(它还允许一些其他的编译时检查,比如确保方法也是静态的)。由于结构体是值类型且不允许多态行为,因此很容易理解为什么不允许使用static。但是,你可以在结构体上拥有静态成员。 - Steve Guidi
2
@Steve:如果类是静态的,编译器还会检查类型名称的使用。例如,您不能声明类型为Enumerable的参数。您可能已经意识到了这一点,但我想引起注意 :) - Jon Skeet
@Jon:没错,谢谢你提醒我。 - Steve Guidi
7个回答

18

一个静态类只是静态成员(可以是任何类型的成员,如字段、事件、属性和最常见的方法)的容器。

一个静态结构体将完全相同,因此不会提供任何优势,但读者可能认为它具有某些特殊含义。为了避免混淆,因此被禁止。从概念上讲,这与静态类的意义一样明确,当然,结构体和类之间的区别实际上是在它们的实例行为方面,并且由于静态类型的实例不存在,所以这种区别是无关紧要的。

(当然,我并没有参加过决定这个问题的设计会议。Eric Lippert 可能能够找到一些有关此事的记录。就我所知,C# 3 注释规范对此事保持沉默。)


2
你的意思是你没有参加设计会议? - Dan Tao
1
@Dan:唉,我从未参加过任何C#设计会议。当然,我非常希望能够参加。 - Jon Skeet
3
我理解了。 :-) 就我个人而言,我认为更好的做法是采用 VB 路线,创建第三种东西——比如一个“模块”,它就像一个静态类一样。一个只包含静态方法的容器在逻辑上既不是值类型也不是引用类型,那么为什么要通过将其称为一种“类”来愚弄人们呢?如果静态类是在 C# 1.0 中发明出来的话,我认为这应该是正确的方式。但既然它们是在 2.0 中出现的,那么就有压力反对新建一个关键字“模块”或其他名称。因为“static”和“class”已经被保留了。 - Eric Lippert
1
他们开了C#的设计会议?我还以为这门语言是Anders Hejlsberg一个人的杰作。 :) - tcrosley
2
@Joan:不是的。我们尽可能地保留了尽量少的关键词。例如,"get"、"set"和"value"在每个版本的C#中都是未保留的,因为设计人员认为程序员希望将它们用作变量名。有关详细信息,请参见http://blogs.msdn.com/b/ericlippert/archive/2009/05/11/reserved-and-contextual-keywords.aspx。其他公司会做出不同的选择;例如,JavaScript的设计人员决定保留Java的每个关键字,无论是否合理,只是为了以防万一他们将来需要使用它们。 - Eric Lippert
显示剩余2条评论

8
这样做没有任何效果。你仍然会像使用静态类时一样拥有一组静态方法。在C#中,结构体表示它是值类型而不是引用类型,在静态级别上没有意义。

3

没有实例字段初始化器

在一个类中,我们可以创建一个字段/变量并同时初始化它。但结构体不能包含这样的初始化。这些字段必须通过函数或使用对象本身进行初始化。字段不能在创建时赋初值。以下代码会报错:

struct Point
{ 
    public int x = 20; // Error its not possible to initialize
    public int y=20; // Error its not possible to initialize
} 

然而,结构体可以包含静态字段,这些字段可以在结构体内部初始化。 以下示例显示了在结构体内使用静态字段的用法。

struct  Point  {
        public static int x = 25;
        public static int y = 50;
}

结构体和方法

C#的结构体也可以包含方法。这些方法可以是静态的或非静态的。但静态方法只能访问其他静态成员,它们不能使用结构体对象来调用。它们只能通过使用结构体名称来调用。

struct Point  
{    
    static int x = 25;    
    static int y = 50;
    public void SetXY(int i, int j)    
    {        
        x = i;        
        y = j;    
    }     

    public static void ShowSum()            
    {        
        int sum = x + y;        
        Console.WriteLine("The sum is {0}",sum);    
    }
}

本文源自 "http://www.csharpfriends.com/articles/getarticle.aspx?articleid=120"

(该文章是关于IT技术的,但具体内容需要进一步提供以获得精确翻译)

3

归类为“事实如此”。由于您可以使用静态类来完成它,因此没有理由允许静态结构体。这只会让人们对它们之间的区别感到困惑。他们必须选择其中之一。


3
此外,由于只有一个实例,我们无法使用构造函数来初始化该类。
实际上,静态类没有任何实例。这也解释了为什么不支持静态结构体,或者说完全没有必要支持这样的东西。
在.NET中,引用类型和值类型(C#中的class和struct)之间的区别完全取决于如何处理这些类型的实例。引用类型的实例通过对该实例的引用以变量形式进行访问。这些引用的副本在方法调用之间传递。值类型的实例直接访问,并且实例本身的副本在方法调用之间传递。
没有实例可言,这种区别变得无关紧要。因此,任何仅由静态成员组成的类型都可以是静态类。

1

静态类型的概念对于结构体来说是没有意义的。 结构体意味着按值复制语义 - 只有在可以实例化类型时才有意义。静态类被引入是为了更容易地将静态方法分组到一个无法实例化的类型中。允许静态结构体既是冗余的,也会令人困惑。

这样想一下。 static class Foostatic struct Foo 的行为有何不同?如果它们没有区别...为什么要引入static struct的概念呢?这只会让人们误以为存在差异...


我理解你的观点。但是“class”肯定意味着按引用复制的语义,能够创建实例,并且通过继承共享实现细节,而静态类都不具备这些条件。很明显静态类并不比静态结构体更好,甚至可以说更差。 - Eric Lippert
@Eric:确实如此...也许第三种概念(正如你在评论Jon的帖子中提到的模块)可能更好。我想我试图表达的是(表达得不好),拥有静态类静态结构体两者将会令人困惑,并暗示了一个不存在的行为差异。 - LBushkin

1
因为静态在语言中没有定义为可应用于结构体。
而 `static class` 已经定义了相同的能力。

古老链接的原因是什么? - John Saunders
@John:感谢你指出这个问题。我已经删除了它。当时我在谷歌上搜索参考页面时,这是我找到的第一个结果。 - Brian R. Bondy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接