C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# 值类型

C# 值类型的实现

作者:诗和远方ya

本文主要介绍了C# 值类型的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、c#类型

类型(Type)又叫数据类型(Data Type)。
A data type is a homogeneous collection of values,effectively prensented,equipped with a set of operations which manipulate these values.

// c#代码
int a = 10;
string str = "Hello, world!";
int b = a + str;

//输出结果为:
//无法将类型“string”隐式转换为“int”
# python代码
a = 10
a = "Hello, world!"

c#类型分为值类型和引用类型,值类型有结构体和枚举,引用类型有类、接口、委托。

在这里插入图片描述

struct MyStruct  // 定义结构体
{

}

Type type = typeof(int); //使用typeof关键字获取int的类型
Console.WriteLine(type.BaseType); //打印int的基类型
Console.WriteLine(type.BaseType.BaseType); //打印int的基类型的基类型

Console.WriteLine("---------");
type = typeof(MyStruct); //使用typeof关键字获取MyStruct的类型
Console.WriteLine(type.BaseType); //打印MyStruct的基类型
Console.WriteLine(type.BaseType.BaseType); //打印MyStruct的基类型的基类型

//输出结果为:
//System.ValueType
//System.Object
//---------
//System.ValueType
//System.Object

2、值类型

值类型的变量存储数据,而引用类型的变量存储对实际数据的引用。

2.1 结构体

结构体和类很相似,结构体通常用来封装小型相关变量组。
与类相比,结构体有一些限制,例如它不能声明为抽象的或密封的,它也不能声明默认构造函数(没有参数的构造函数)和析构函数。结构体通常用于小型、不可变的数据结构,而类更适合用于需要更复杂行为的对象。
结构体在C#中是实现轻量级数据结构的强大工具,它在性能上通常优于类,因为它避免了垃圾回收的开销。然而,它也有一定的限制,比如不能被声明为可空的,并且当结构体包含引用类型字段时,可能会引入垃圾回收的开销。
结构体可以包含构造函数、 常量、 字段、 方法、 属性、 索引器、 运算符、 事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。

struct Student
{
	public int age;
	public int height;
	public double weight;
	public string name;
}

我们不能在结构体中初始化实例字段,可以在结构体中初始化静态字段以及常量。

struct Student 
{
	public static int avgAge = 10;  //可以在结构体中初始化静态字段
	public const int height = 100;  //可以在结构体中初始化常量
	public int age;  //不能在结构体中初始化实例字段
}

要想初始化实例字段,有两种方法:一是使用参数化构造函数,二是在声明结构后分别访问成员。

struct Student 
{
	public Student(int x)
	{
		age = x;
	}
	//public static int avgAge = 10;
	public int age;
}

Student stu = new Student(10);  //使用参数化构造函数初始化实例字段
Console.WriteLine(stu.age);
stu.age = 20;  //声明结构后访问实例字段
Console.WriteLine(stu.age);

//输出结果为:
//10
//20

与类不同,结构的实例化可以使用new运算符,也可以不使用。如果使用的话,会创建该结构的对象,并调用构造函数,构造函数不传入参数的话,调用的是默认构造函数,默认构造函数会对结构体的成员进行初始化;如果不使用的话,就不会调用构造函数,在初始化所有字段之前,字段将保持未赋值状态且对象不可用。

struct Student 
{
	public int age;
	public int height;
}

Student stu1; //不使用new创建对象
Student stu2 = new Student();  //使用new创建对象,并调用构造函数
struct Student 
{
	public int age;
	public int height;
}

Student stu1; //不使用new创建对象
Console.WriteLine(stu1.age);

//输出结果为:
//使用了可能未赋值的字段"age"

所以正确的做法应该是:

struct Student 
{
	public int age;
	public int height;
}

Student stu1; 
stu1.age = 10;
stu1.height = 130;
Console.WriteLine(stu1.age);
Console.WriteLine(stu1.height);
struct Student 
{
	public int age;
	public int height;
}

Student stu2 = new Student(); 
Console.WriteLine(stu1.age);
Console.WriteLine(stu1.height);

2.2 枚举

枚举类型用enum关键字进行声明,它是一种由一组称为枚举数列表的命名常量组成的独特类型。
通常情况下,最好是在命名空间内直接定义枚举,以便该命名空间中的所有类都能够同样方便地访问它。 但是,还可以将枚举嵌套在类或结构中。
默认情况下,第一个枚举数的值为 0,后面每个枚举数的值依次递增 1。

namespace ConsoleApp1
{
    enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((int)Days.Mon);
            Console.WriteLine((int)Days.Tue);
            Console.WriteLine((int)Days.Wed);
        }
    }
}

//输出结果为:
//0
//1
//2

当然,也可以强制元素序列从1开始。

namespace ConsoleApp1
{
    enum Days { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun };
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((int)Days.Mon);
            Console.WriteLine((int)Days.Tue);
            Console.WriteLine((int)Days.Wed);
        }
    }
}

//输出结果为:
//1
//2
//3

枚举类型的默认基础类型是int,所以,上述代码中定义枚举类型变量的完整表达为:

enum Days:int { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun };

枚举类型变量可赋以基础类型范围内的任何值,准许使用的枚举类型有 byte、 sbyte、 short、 ushort、 int、 uint、 long 或 ulong。

namespace ConsoleApp1
{
    enum Days:byte { Mon=1, Tue=2, Wed=10, Thu=20, Fri=30, Sat=100, Sun=255 };
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((byte)Days.Mon);
            Console.WriteLine((byte)Days.Tue);
            Console.WriteLine((byte)Days.Wed);
            Console.WriteLine((byte)Days.Thu);
            Console.WriteLine((byte)Days.Fri);
            Console.WriteLine((byte)Days.Sat);
            Console.WriteLine((byte)Days.Sun);
        }
    }
}

//输出结果为:
//1
//2
//10
//20
//30
//100
//255

在switch语句中使用枚举值。

namespace ConsoleApp1
{
    enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
    class Program
    {
        static void Main(string[] args)
        {
            Days day = (Days)1;
            switch (day)
            {
                case Days.Mon:
                    Console.WriteLine("Today is Mon");
                    break;
                case Days.Tue:
                    Console.WriteLine("Today is Tue");
                    break;
                case Days.Wed:
                    Console.WriteLine("Today is Wed");
                    break;
                case Days.Thu:
                    Console.WriteLine("Today is Thu");
                    break;
                case Days.Fri:
                    Console.WriteLine("Today is Fri");
                    break;
                case Days.Sat:
                    Console.WriteLine("Today is Sat");
                    break;
                case Days.Sun:
                    Console.WriteLine("Today is Sun");
                    break;
            }
        }
    }
}

使用枚举类型的好处:

enum Days:byte { Mon=1, Tue=2, Wed=10, Thu=20, Fri=30, Sat=100, Sun=255 };
Days day = Days.Mon;

在这个程序中,一个星期只能包含从星期一到星期日的7天,所以只能取枚举中的值。

我们可以使用扩展方法为枚举类型添加功能。

namespace ConsoleApp1
{
    // 在非泛型静态类中定义扩展方法
    public static class Extensions
    {        
        public static Grades minPassing = Grades.D;
        // this关键字在方法定义中用于指定这是一个扩展方法
        //this关键字后面跟着的是类型参数,表示这个扩展方法可以被任何Grade类型的实例调用
        public static bool Passing(this Grades grade)  
        {
            return grade >= minPassing;
        }
    }

    public enum Grades { F = 0, D=1, C=2, B=3, A=4 };
    class Program
    {       
        static void Main(string[] args)
        {
            Grades g1 = Grades.D;
            Grades g2 = Grades.F;
            Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
            Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");

            Extensions.minPassing = Grades.C;
            Console.WriteLine("\r\nRaising the bar!\r\n");
            Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
            Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
        }
    }
  }
}

/* 输出结果为:
    First is a passing grade.
    Second is not a passing grade.

    Raising the bar!

    First is not a passing grade.
    Second is not a passing grade.
 */

实际上,通过枚举类型实例对扩展方法的调用,等效于调用普通非扩展方法的方式。也就是说,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。

Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
// 等效于
Console.WriteLine("First {0} a passing grade.", Extensions.Passing(g1) ? "is" : "is not");
Console.WriteLine("First {0} a passing grade.", Extensions.Passing(g2) ? "is" : "is not");

到此这篇关于C# 值类型的实现的文章就介绍到这了,更多相关C# 值类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文