概述
同学们是否还记得,我们在讲类型转换的时候,有过这样的写法:
int.Parse("23");
以前我们知道,Parse()是一个方法;现在我们可以想一想,Parse()究竟是谁的方法了。要知道答案,非常简单,光标停留在Parse()上,直接F12转到定义,结果我们就看到了:
这什么意思?我们看到了Parse()是Int32的一个静态方法。而Int32又是什么?它是一个
结构(struct)
结构是一个和类(class)非常非常相似的封装容器。它的成员和语法,和类几乎一模一样。除了上面的静态方法调用,还可以:
//new一个结构实例,生成它的实例对象
int age = new Int32();
//调用结构的实例方法
age.CompareTo(21);
但是,结构
- 能够实现接口,但不能继承其他结构和类,自然也不能被其他结构和类继承(这可能是结构较少使用的一大原因);
- 默认有一个无参构造函数,但不能显式声明。有参构造函数可以显式声明,声明的有参构造函数也不会“隐藏”默认的无参构造函数。但构造函数必须保证结构中的所有字段和自动属性被赋值。
我们可以自己创建一个结构,试一试:
internal struct Bed //源栈同学的床位
{
//public Bed(){} //报错
//报错:没有给_id赋值
//public Bed(string room)
//{
// Room = room;
//}
private int _id;
internal string Room { get; set; }
public bool HasBooked;
}
你也许会奇怪为什么结构的构造函数要要求这么多?因为结构类型是 值类型 。而值类型要求其所有成员必须有值!如果使用结构默认的无参构造函数,结构会自动的给所有成员赋默认值;否则,这些所有成员都必须在有参构造函数中被赋值。
一个比较“奇怪”的语法可以帮助你记住这一点:
Bed dream /*= new Bed()*/; //所以wx没有指向任何对象
dream.HasBooked = true; //但wx.HasBooked可以直接被赋值
Console.WriteLine(dream.HasBooked); //想一想true值被存放到哪里了
如果Bed不是struct而是class的话,这样的代码是会报错的:因为引用类型变量dream无法存放HasBook的值。但当dream是struct的时候,dream.HasBooked是直接存放在dream中的,所以可以赋值。
注意如果注释掉上面第2行代码,你会发布无法通过编译,因为dream.HasBooked没有被赋值;但注释掉第2行代码的同时取消掉第1行代码的注释,你会发现又OK了:
Bed dream = new Bed(); //new Bed()实际上给所有struct成员赋了默认值
//dream.HasBooked = true;
Console.WriteLine(dream.HasBooked);
同样因为结构是值类型,值类型的优势是直接存放在栈中,可以快速读取;但它的数据量不能太大,否则就会耗用栈空间,反而拖累性能。(引用类型的优势:只赋值地址不copy内容,传递时更快……)
另外,注意结构不能继承,所以诸多面向对象的特性它都不能使用,所以实际开发中用得并不多。
常用的结构都是C#里的内置(build-in)类型。int其实是Int32的别名,double是Double的别名,bool是Boolean的……所有关键字定义的内置类型,除了string和object,其他全部都是值类型,又被称之为简单类型。(详见:内置类型表 - C# 参考)
我们接下来要详细介绍的,是
DateTime,包括日期(年月日)和时间(小时分钟秒等)。.NET为我们提供了大量关于日期的属性和方法,以方便我们的开发。
演示F12查看metadata:……
最常用的包括:
1)构造函数:通过new DateTime()构造一个时间对象,可以指定年月日小时分钟秒等:
//2019年12月1日
DateTime date = new DateTime(2019, 12, 1);
//2019年12月1日 19点52分24秒
DateTime dateTime = new DateTime(2019, 12, 1, 19, 52, 24);
2)静态属性:DateTime.Now,获取当前时间
Console.WriteLine(DateTime.Now);
3)实例属性:根据时间变量取得它的年月日(Day/Year/Month)等,通常和DateTime.Now 搭配使用:
Console.WriteLine(DateTime.Now.Day); //当月的第几日
4)实例方法:在现有时间基础上增减,比如AddDays()/AddMonths()/AddYears()……
5)ToString()方法:可以用于指定日期显示的格式。通常,我们使用字符串指定。用y代表year,用M(注意大写)代表month,用d代表day等,如下所示:
Console.WriteLine(DateTime.Now.ToString(
"yyyy年MM月dd日 hh点mm分ss秒"));
//显示:2019年12月01日 07点59分14秒
另外,注意DateTime中已经出现了:
TimeSpan,它也是一个struct,表示的是一段时间,通常由两个日期相减获得。注意:
- Timespan计量的最大单位是天(Days),没有年和月
- 用Days/Hours/Minutes等取出的是Timespan中天/小时/分钟等 部分 的值
- 用TotalDays/TotalHours/TotalMinutes等取出的才是Timespan代表的时间间隔换算成天/小时/分钟等的值
TimeSpan span =
new DateTime(2020, 8, 24, 3, 2, 12) -
new DateTime(2019, 7, 12, 9, 0, 0);
Console.WriteLine(span); //408.18:02:12
Console.WriteLine(span.Days); //408
Console.WriteLine(span.TotalDays); //408.751527777778
Console.WriteLine(span.Hours); //18
Console.WriteLine(span.TotalHours); //9810.03666666667
Console.WriteLine(span.Minutes); //2
Console.WriteLine(span.TotalMinutes); //588602.2
Timespan以后在学习缓存的时候会非常有用。
另外,阅读源代码的时候,我们还发现了这样的代码:
public static DateTime operator +(DateTime d, TimeSpan t);
这被称之为
运算符重载
实际上就是改变了运算符加号(+)的运算逻辑:本来加号是只能用于数值型类型的,DateTime显然不是数值,本是不应该能够使用加号的,然而:
Console.WriteLine(DateTime.Now + new TimeSpan(5000));
这就是因为在DateTime类中,进行了上述运算符重载。
任何一个类都可以进行运算符重载,比如我们的Student类:
其语法要求是:
- 方法只能是public和static的
- 必须要有一个关键字operator
- 至少一个参数和返回值类型相匹配
- 某些运算符有要求“成套”,比如重载了==,就必须重载 !=
另外,不是所有运算符都可以重载。具体可查看:可以重载的运算符
和运算符重载非常类似的,还有一种语法:
类型转换重载
前面我们知道,类型之间的强转,本来只能发生在
我们可以用一个类
通常我们不会主动使用运算符和类型转换重载,但随着.NET core的开源,我们将越来越多的遇到
每日单词:
作业:
- 用代码证明struct定义的类型是值类型
- 源栈的学费是按周计费的,所以请实现这两个功能:
- 函数GetDate(),能计算一个日期若干(日/周/月)后的日期
- 给定任意一个年份,就能按周排列显示每周的起始日期,如下图所示:
注意:先写测试用例,确保所有测试用例通过
感谢童鞋们的阅读!^_^
我就是:黑律师/包工头/创业狗/老码农……现在还是教书匠的大飞哥。
再次重申这个系列的目标是:
1)通俗易懂。2)实战为主。3)面向就业。
系列内容的完善需要你的反馈!
欢迎点赞和评论,以及加入我们的QQ交流群:326801052。
最后
以上就是爱撒娇方盒为你收集整理的结构中不能实例属性_C#-面向对象-结构和日期的全部内容,希望文章能够帮你解决结构中不能实例属性_C#-面向对象-结构和日期所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复