原作者:Nishant S

Introduction

Just about everything is a heap object when you are using C#. Only elementary native types like int are treated as value types. But there are two value types in C# that are pretty much more useful that first glances would tell you. They are the enum and struct types. Very few tutorials even cover these topics, but they have their own uses. And both of them are a lot more efficient than classes and you can use them in place of classes when they meet your requirements to improve performance.

介绍

当你使用C#时,几乎所有东西都是储存在堆上的对象。只有基本的原生类型比如说 int 作为值类型创建。但有两种值类型当你第一眼看到时就会觉得更加有用。它们是enum 跟struct类型。几乎没有指导书有这两个类型的主题,但它们自有用处。而且它们两个都有比类更加有效率的地方。当你有需要改善你的程序的时候,你可以用它们两个来代替类。

Enums

Enums are basically a set of named constants. They are declared in C# using the enum keyword. Every enum type automatically derives from System.Enum and thus we can use System.Enum methods on our Enums. Enums are value types and are created on the stack and not on the heap. You don't have to use new to create an enum type. Declaring an enum is a little like setting the members of an array as shown below.

枚举

Enums(枚举)基本上是一些取了名的常量的集合。它们在C# 中用 enum 关键字声明。所有的枚举类型都自动(隐含)得从System.Enum继承,所以我们可以在我们自己的枚举类型中使用System.Enum中的方法。枚举是值类型,它被创建在堆栈上而不是堆上。你不必使用new操作符来创建一个枚举类型。声明一个枚举有点像为一个数组设置数组成员,如下所示:

You can pass enums to member functions just as if they were normal objects. And you can perform arithmetic on enums too. For example we can write two functions, one to increment our  enum and the other to decrement our enum.

你可以把枚举传递给成员函数就好像它们是普通的对象。你也可以在枚举上进行算术运算。比如说我们写了两个函数,一个用来使我们的枚举自增(increment),而另一个用来使它自减(decrement)。

Rating IncrementRating(Rating r)
{
    if(r == Rating.Excellent)
        return r;
    else
        return r+1;
}
Rating DecrementRating(Rating r)
{
    if(r == Rating.Poor)
        return r;
    else
        return r-1;
}

Both functions take a Rating object as argument and return back a Rating object. Now we can simply call these functions from elsewhere.

两个函数都把Rating对象作为参数,同时返回一个Rating对象值。现在我们就可以从任何地方简单地调用这些函数了

for (Rating r1 = Rating.Poor; 
    r1 < Rating.Excellent ; 
    r1 = IncrementRating(r1))
{           
    Console.WriteLine(r1);
}

Console.WriteLine();

for (Rating r2 = Rating.Excellent; 
    r2 > Rating.Poor; 
    r2 = DecrementRating(r2))
{
    Console.WriteLine(r2);          
}

And here is a sample code snippet showing how you can call System.Enum methods on our Enum object. We call the GetNames method which retrieves an array of the names of the constants in the enumeration.

这是一个示例代码小片段,用来展示我们如何调在我们的Enum对象里用System.Enum中的方法。我们可以使用GetNames方法来得到一个数组,这个数组包含定义在枚举中的常量成员。

Where to use enums

Quite often we have situations where a class method takes as an argument a custom option. Let's say we have some kind of file access class and there is a file open method that has a parameter that might be one of read-mode, write-mode, read-write-mode, create-mode and append-mode. Now you might think of adding five static member fields to your class for these modes. Wrong approach! Declare and use an enumeration which is a whole lot more efficient and is better programming practice in my opinion.

哪里该使用枚举

我们经常遇到这种情况,一个类的方法把参数作为自选项。比如说我们有某个文件存取类,其中有一个打开文件的方法,它有一个参数,可能是只读模式,只写模式,读写模式,创建模式,追加模式中的一种。这时你可能想为这些模式加5个静态字段作为类成员。错了!在我看来,声明和使用枚举效率高得多的了,是一个更好的编程习惯。

(PS:我把argument跟parameter都翻译成参数,但是不知道它们的区别,希望高手指点)
    (经过Ninputer指出,应该是argument是“实参” ,parameter是“形参” )

Structs

In C++ a struct is just about the same as a class for all purposes except in the default access modifier for methods. In C# a struct are a pale puny version of a class. I am not sure why this was done so, but perhaps they decided to have a clear distinction between structs and classes. Here are some of the drastic areas where classes and structs differ in functionality.

  • structs are stack objects and however much you try you cannot create them on the heap
  • structs cannot inherit from other structs though they can derive from interfaces
  • You cannot declare a default constructor for a struct, your constructors must have parameters
  • The constructor is called only if you create your struct using new, if you simply declare the struct just as in  declaring a native type like int, you must explicitly set each member's value before you can use the struct

结构

在C++里,除方法的默认访问修饰符,任何情况结构都跟类是一样的。(我没学过C++,就不知道这个是什么意思了)。在C#里,结构可以算是一种功能较弱的类。我不确定为什么会被这样处理,可能他们决定让结构跟类有一个明确的区别。下面是一些类跟结构在功能上明显不同的地方:

  • 无论你多想把结构创建在堆上,结构都是存放在堆栈上的对象
  • 一个结构无法从另一个结构继承,但它们可以继承接口(实现接口)
  • 你不能为结构声明一个默认构造器 ,你的构造器必须有参数
  • 只有在你创建结构的时候使用new操作符,构造器才会被调用。如果你只是简单的声明结构就像声明原生类型int那样,你就必须在使用这个结构以前,显式地为每个结构的成员赋值。
struct Student : IGrade
{   
    public int maths;
    public int english;
    public int csharp;

    //public member function
    public int GetTot()
    {
        return maths+english+csharp;
    }

    //We have a constructor that takes an int as argument
    public Student(int y)
    {
        maths = english = csharp = y;
    }

    //This method is implemented because we derive
    //from the IGrade interface
    public string GetGrade()
    {
        if(GetTot() > 240 )
            return "Brilliant";
        if(GetTot() > 140 )
            return "Passed";
        return "Failed";
    }
}

interface IGrade
{
    string GetGrade();
}

Well, now let's take a look at how we can use our struct.

好了,现在让我们来看看怎么使用我们的结构。

Here the default constructor gets called. This is automatically implemented for us and we cannot have our own default parameter-less constructor. The default parameter-less constructor simply initializes all values to their zero-equivalents. This is why we get a 0 as the total.

这里默认构造器被调用了。这是自动执行的,我们不能有自己的默认无参构造器(default parameter-less constructor我不知道这样翻译对不对,但我觉得应该是这个意思)。默认无参构造器只是简单地把所有值初始化为它们的0等价值(zero-equivalents,虽然翻译的不伦不类的,但我想大家应该知道是什么意思,哈),这就是为什么我们的total变量得到了0值。

Because we haven't used new, the constructor does not get called. Of all the silly features this one must win the annual contest by a long way. I see no sane reason why this must be so. Anyway you have to initialize all the member fields. If you comment out the line that does the initialization you will get a compiler error :- Use of unassigned local variable 's2'

因为我们没有使用new操作符,构造器就没有被调用。在所有愚蠢的特性中,这一个定会在年度讨论会中压倒性胜出。我没有发现任何健全的理由为什么这样做。总之你必须自己初始化所有成员字段。如果你把那行(初始化所有成员字段的那行)注释掉,你会得到一个编译器错误:

error CS0165: 使用了未赋值的局部变量“s2”(这是我的编译器显示的,哈)

This time we use our custom constructor that takes an int as argument.

这次我们的自定义构造器把一个int作为参数了。

When to use structs

Because structs are value types they would be easier to handle and more efficient that classes. When you find that you are using a class mostly for storing a set of values, you must replace those classes with structs. When you declare arrays of structs because they are created on the heap, efficiency again improves. Because if they were classes each class object would need to have memory allocated on the heap and their references would be stored. In fact lots of classes within the .NET framework are actually structs. For example System.Drawing.Point is actually a struct and not a class.

什么时候该使用结构

因为结构是值类型,它们比类更加易于操作,更加有效率。当你发现你正在使用一个类主要用于储存一些值的集合,你就必须用结构代替类。当你声明一个结构数组,由于它们被创建在堆上,效率又一次被提高了。如果它们是类,则每一个类的对象都要在堆上分配空间,它们的对象的引用就被储存了(我觉得引用应该是在堆栈上)。事实上很多.NET框架里的类实际上是结构。比如说System.Drawing.Point实际上是一个结构而不是一个类。

原文及源代码请参见
http://www.codeproject.com/csharp/csenums01.asp

Enums and Structs in C#(C#里的枚举和结构) (from codeproject)相关推荐

  1. MyBatis对于Java对象里的枚举类型处理

    平时咱们写程序实体类内或多或少都会有枚举类型属性,方便嘛.但是mybatis里怎么处理他们的增删改查呢? 要求: 插入的时候,会用枚举的定义插入数据库,我们希望在数据库中看到的是数字或者其他东西: 查 ...

  2. TypeScript 里的枚举类型 enum

    官网地址 枚举是 TypeScript 为数不多的不是 JavaScript 类型级扩展的特性之一. 枚举允许开发人员定义一组命名常量. 使用枚举可以更轻松地记录意图,或创建一组不同的案例. Type ...

  3. Marketing Cloud里Odata请求响应结构的解析

    代码应该怎么写呢? 从调试器里看到响应结构是一个巨大的json对象,顶层属性名为d: 然后是results属性,这是一个数组. 所以最后的代码为: function displayResult(oRe ...

  4. 【原创】VBA里的枚举型数据enum

    一 比较三种数据类型 enum   枚举型,数值类型  eNum array    数组 dictionary   字典 二 枚举型 1.1 枚举型  enum  需要先用户自定义 放在过程外,模块最 ...

  5. C里的共同体和结构体的区别

    共用体 构造数据类型,也叫联合体 用途:使几个不同类型的变量共占一段内存(相互覆盖) 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体-------自定义数据 结构体变量所占内存长度是各 ...

  6. 从表到里学习JVM实现

    在社会化分工.软件行业细分专业化的趋势下,会真的参与到底层系统实现的人肯定是越来越少(比例上说).真的会参与到JVM实现的人肯定是少数.  但如果您对JVM是如何实现的有兴趣.充满好奇,却苦于没有足够 ...

  7. Go 语言里怎么正确实现枚举?答案藏着官方的源码里

    在编程领域里,枚举是用来表示只包含有限数量的固定值的类型,在开发中一般用于标识错误码或者状态机.拿一个实体对象的状态机来说,它通常与这个对象在数据库里对应记录的标识状态的字段值相对应. 在刚开始学编程 ...

  8. sap 新建事务_SAP GUI里的收藏夹事务码管理工具

    本文是2020年第13篇原创文章,也是汪子熙公众号总共第196篇原创文章. 今天是2020年1月20日,农历大年二十六,年味渐浓. Jerry的老家,从成都乘坐高铁只要十五分钟就能到达,所以从来不会遭 ...

  9. 1. 在 SAP ABAP 事物码 SEGW 里创建 SAP OData 项目

    从本文开始,我们迈出使用事物码 SEGW 开发 OData 服务的第一步. 我们会开发一个能够进行图书管理(Book Management) 的 OData 服务,首先创建一个图书实体的模型,也就是 ...

最新文章

  1. binlog/redolog/undolog?再也不会傻傻分不清楚了
  2. Linux虚拟内存,你理解到位了?
  3. 特征工程与sklearn
  4. WordPress永久链接 静态化教程
  5. thinking-in-java(10)内部类
  6. Pytorch(5)-梯度反向传播
  7. 【Webpack】TypeError: Cannot read property ‘tap‘ of undefined at HtmlWebpackPlugin.
  8. 新书《Ext JS 4.2 实战》终于出炉了
  9. Wattagio for Mac(电池管理) 免激活版
  10. 更改win7脱机文件夹位置
  11. 计算机基础17秋在线作业3,西南大学17秋1056《计算机基础》在线作业(参考资料)...
  12. 【不误正业】win10透明任务栏,任务栏居中+桌面美化工具DeskGo
  13. FishC笔记—16 讲 序列,序列
  14. 用ps制作LOGO(个人向)
  15. 锐龙r7 4750u和i7 10510u 哪个好
  16. java日志脱敏_java 日志脱敏框架 sensitive,优雅的打印脱敏日志
  17. SumatraPDF一个很nice的PDF开源项目
  18. 什么是幂等性、幂等性解决方案
  19. 财路网每日原创推送: 创世区块10年:记住这群加密狂魔
  20. Java 8新特性(三):Optional类

热门文章

  1. 徐雷FrankXu 内推 杭州 蚂蚁金服招聘 java开发工程
  2. asp.net mvc处理css和js版本问题
  3. 线性模型(1) —— 多元线性回归
  4. isc-dhcp监听网口的实现步骤
  5. windows7开启虚拟wifi和虚拟无线AP的方法
  6. linux挂载NTFS硬盘
  7. SSIS常用的包—大量插入任务(Bulk Insert task)
  8. 探讨ASP.NET 2.0中的Web控件改进技术(2)
  9. 笔记本电脑与漂亮老婆
  10. 生产环境中on yarn模式是否采用yarn session