C#中struct和class的使用区别是什么?

class是引用类型,struct是值类型

引用类型在堆上,值类型是内联的。

值类型有全部的值的内容,而引用类型只有一个地址。

值类型总是有一个值,而引用类型指针可以为空。

  1. 为了优化减少体积
  2. 需要传递给c++程序
  3. 当作参数传递

除了以上,尽量用class。

 

 

 

struct选择基准:

●设计上

1. 倾向于“载体”,“容器”的概念

(比如其他对象的副本,部分副本,数据的集合...)

2. 无状态性(或简单状态)

(状态相当于一个处于对象生命周期内的东西,存储了状态,即说明对象一般需维持一个较长生命周期)

3. 不具有复杂功能,逻辑。甚至于没有功能。

(仅包含get/set, ctor/dtor, isvalid...基本功能)

●限制,需求等因素

1,内容短

2,限制:

不需要设为null,不需要做方便的初始化(比如泛型内 out参数)

不需要使用引用修改的便捷性(修改一个,所有引用可见)

不能有继承性

3,频繁构建,销毁

4,c/c++兼容性

看过一些C++的struct和class选择文章,道理差不多,更多的从设计根本上去剖析,还是很不错的,有些思想值得多参考。

也有些属于语言的层面的坑,需要注意,比如非引用类型在C#中的种种限制,比如C++的struct和class具备几乎完全相同性质

虽说C#/C++语言特性不同,但是在设计上,从问题本质出发的思考上,结论应该是是具备较大相似性的。

 

 

1、比如如下定义:

    class Student_C
    {
        public Student_C(string n, int s) { name = n; score = s; }

        public string name;
        public int score;
    }

    struct Student_S
    {
        public Student_S(string n, int s) { name = n; score = s; }

        public string name;
        public int score;
    }

2、引用类型和值类型相比,在创建对象、赋值等基本操作时,含义完全不同。

    class Program
    {
        static void Main(string[] args)
        {
            Student_C s1 = new Student_C("小明", 80);
            Student_C s2 = s1;
            // 以上代码在堆上创建了一个"小明"对象,变量s1和s2都指向这个对象

            Student_S ss1 = new Student_S("小红", 70);
            Student_S ss2 = ss1;
            // 以上代码在栈上创建了 两个 临时对象
            // ss1和ss2是两个独立的学生对象,只是内容相同
        }
    }

当我们认识到,即便对于最基本的创建赋值操作,class和struct都是不同的,就会逐步想清楚它们的区别了。

 

总的来说,C#的struct是为了加速局部对象的处理,包括创建、运算和销毁。所以只有小且频繁的对象才用struct。

例如,Unity中表示坐标的Vector2、Vector3,表示旋转的Quaternion,适合用struct。

它们有两个特点:数据量相当小,只有8~16个字节;计算坐标时会大量创建和使用临时对象。

在这种情况下,使用struct是最合适的。能够减少GC,赋值操作也方便。

除此以外,大多数情况使用class都是更不错的选择。

 

最后直接回答题主的问题。

1、有一个创建视图的接口,由于参数很多,因此对参数进行封装,封装的参数应该使用class还是struct?

根据题主的字面意思。由于参数数量不确定(未来还可能添加)、字段类型不统一,不满足struct的优化条件,建议使用class。

2、生成excel配置文件对应的class,配置表中的一行数据应该对应一个class还是struct?

从配置文件中读取的数据,一般都是要长期使用的,不存在频繁创建销毁问题;且每一行的数据量估计在十几字节到几百字节不等。所以很可能不满足struct的优化条件,仍然建议使用class。

 

C# 中 Struct 和 Class 的区别总结

技术译民

技术译民

公众号:技术译站,专注IT 技术。一个技术译民的『技术译站』

​关注他

6 人赞同了该文章

 

翻译自 Manju lata Yadav 2019年6月2日 的博文  《Difference Between Struct And Class In C#》,补充了一些内容和示例。

结构体(struct)是类(class)的轻量级版本。结构体是值类型,可用于创建行为类似于内置类型的对象。

比较

结构体和类共享许多特性,但与类相比有以下局限性。

  • 结构体不能有默认构造函数(无参构造函数)或析构函数,构造函数中必须给所有字段赋值。
  public struct Coords
  {
      public double x;
      public double y;
    
      public Coords() //错误,不允许无参构造函数
      {
          this.x = 3;
          this.y = 4;
      }
        
      public Coords(double x) //错误,构造函数中必须给所有字段赋值
      {
          this.x = x;
      }
        
      public Coords(double x) //这个是正确的
      {
          this.x = x;
          this.y = 4;
      }
    
      public Coords(double x, double y) //这个是正确的
      {
          this.x = x;
          this.y = y;
      }
  }
  • 结构体是值类型,在赋值时进行复制。
  • 结构体是值类型,而类是引用类型。
  • 结构体可以在不使用 new 操作符的情况下实例化。 例如:
  public struct Coords
  {
      public double x;
      public double y;
  }
    
  static void Main()
  {
      Coords p;
      p.x = 3;
      p.y = 4;
      Console.WriteLine($"({p.x}, {p.y})");  // 输出: (3, 4)
  } 
  • 结构体不能继承于另一个结构体或者类,类也不能继承结构体。所有结构体都直接继承于抽象类 System.ValueTypeSystem.ValueType 又继承于 System.Object
  • 结构体不能是基类,因此,结构体不能是 abstract 的,且总是隐式密封的(sealed)。
  • 不允许对结构体使用抽象(abstract)和密封(sealed)修饰符,也不允许对结构体成员使用 protected 或 protected internal 修饰符。
  • 结构体中的函数成员不能是抽象的(abstract)或虚的(virtual),重写(override)修饰符只允许重写从 System.ValueType 继承的方法。
  • 结构体中不允许实例属性或字段包含初始值设定项。但是,结构体允许静态属性或字段包含初始值设定项。 例如:
  public struct Coords
  {
      public double x = 4; //错误, 结构体中初始化器不允许实例字段设定初始值
      public static double y = 5; // 正确
      public static double z { get; set; } = 6; // 正确
  } 
  • 结构体可以实现接口。
  • 结构体可以用作 nullable type(即:Nullable<T> 中的 T),对其赋值 null 值,参考【Nullable<T> Struct

什么时候使用结构体或类?

要回答这个问题,我们应该很好地理解它们的差异。

这样,结构体(struct)只能在确定以下情形时使用:

  • 它在逻辑上表示单个值,比如基本类型(intdouble,等等)。
  • 它是不可变的(immutable)。
  • 它不会频繁地装箱和拆箱。

在所有其他情形,应该将类型定义为类(class)。

结构体示例:

struct Location
{
    public int x, y;
    public Location(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

static void Main()
{
    Location a = new Location(20, 20);
    Location b = a;
    a.x = 100;
    Console.WriteLine(b.x);
}

输出将是 20。“b” 的值是 “a” 的副本,因此 “b” 不受 “a.x” 更改的影响。但是在类中,输出将是 100,因为变量 “a” 和 “b” 引用同一个对象。


 

以下为译者补充

结构体实例与类实例

结构体实例的内存在栈(stack)上进行分配,所占用的内存随声明它的类型或方法一起回收。 这就是在赋值时要复制结构体的一个原因。 相比之下,类实例的内存在堆(heap)上进行分配,当对类实例的所有引用都超出范围时,为该类实例分配的内存将由公共语言运行时自动回收(垃圾回收)。

结构体实例的值相等性

两个结构体实例的比较是基于值的比较,而类实例的比较则是对其引用的比较。

若要确定两个结构体实例中的实例字段是否具有相同的值,可使用 ValueType.Equals 方法。 由于所有结构体都隐式继承于 System.ValueType,因此可以直接在其对象上调用该方法,如以下示例所示:

public struct Person
{
    public string Name;
    public int Age;
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

static void Main()
{
    Person p1 = new Person("技术译站", 100);
    Person p2;
    p2.Name = "技术译站";
    p2.Age = 100;

    if (p2.Equals(p1))
        Console.WriteLine("p2 和 p1 有相同的值。");

    Console.ReadKey();
}
// 输出: p2 和 p1 有相同的值。

System.ValueType 的 Equals 是使用反射实现的,因为它必须能够确定任何结构体中有哪些字段。 在创建自己的结构体时,重写 Equals 方法可以提供特定于你的类型的高效求等算法。

“基于值的相等”这一点和 C# 9.0 中新增的记录(record) 类型具有相似之处,想了解 C# 9.0 可以查看:欢迎来到 C# 9.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangchuang2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值