啊...这两天一直在忙活AC自动机和数据库的东西... C#都没怎么看... 今天继续学习(填坑...)
类成员: readonly可以用于修饰类成员,性质与const差不多但是const是在编译期间确定,readonly是在运行时确定的。static关键字用于指定某个class固有的内容(变量或者方法). get和set我一直理解为C++的那种private成员对应的public getter/setter但是今天终于发现其实理解错了。例如如下的代码
class testclass
{
public int MyInt
{ get; set; }
}
我一直以为C#会自动生成两个方法setMyInt()和getMyInt()但是后来我才发现其实这其实就是相当于MyInt一个变量而已。可以在get或set上进行权限控制比如protected set等等. 也可以细化get与set,在get和set中加入访问控制或者日志记录比如这样
class testclass
{
private int realValue;
public int MyInt
{
get
{
return realValue;
}
set
{
if (value < 10) realValue = value;
}
}
}
此时如果赋给MyInt的值大于等于10将不会更改realValue的值。其实还是对私有成员的一定包装。(顺便说Visual Studio C# 真是贴心... 只要是访问不到的东西在IDE里面根本看不见(就是那个小的浮动弹出提示窗口) 而C++的IDE总是会把private的方法以及变量展示出来... 干瞪眼不能用...)
类方法: 派生类可以选择重写基类提供的方法,前提是这个方法必须是虚方法而且重写的时候必须加上override ( public override void MethodName() ) . override时可以指定sealed. 如果不是virtual方法不能使用override关键字,只能使用new关键字( new public void MethodName() ). 举个例子
public class baseclass
{
public virtual void A()
{
}
public void B()
{
}
}
public class derivedclass : baseclass
{
public override void A()
{
}
new public void B()
{
}
}
这里面derivedclass中的A()因为在基类中是virtual的因而必须使用override进行重写, 同时由于使用了override, 访问控制(public)必须和基类方法一致, 返回类型也需要保持一致。另外如果参数表不同其实是算作两个函数的(重载函数也是两个不同的函数),因而如果基类是public virtual void A()而派生类是public void A(int a)其实是完全没有问题的。对于new也是一样。
base与this: 构造函数可以使用base关键字来强调构造过程中执行的父类构造函数以及参数(例如 public derivedclass() : base(3) {} ,假设基类有带一个int的构造方法...) 用于构造函数的this关键字可以指定执行本层级的被描述构造方法前执行某个另外的构造方法. (例如derivedclass有两个构造方法,一个是无参数的,另一个是(int,int)构造的,这时无参的构造函数可以使用public derivedclass() : this (2,3) { } 调用derivedclass.derivedclass(2,3)构造. (在C++中不用this而是直接写构造方法名字) . 当this用于类内部时类似于C++里的this指针. this可以被当做参数传递给其他方法,相当于传递了对象自身的引用. this也可以用来指定类的成员(例如this.someData,虽然与someData效果一样),可以明显的区分局部成员和类成员.
类嵌套: class里面可以定义class,这在C++中也很常见. 与C++类似的,C#中嵌套类中内层的类有访问外层类私有成员或方法的权限。如下
C++
class testclass
{
private:
int val;
public:
testclass() :val(0){}
int getVal(){return val;}
class innerclass
{
public:
void setValue(testclass& A,int value)
{
A.val=value;
}
};
};
C#
public class testclass
{
private int val;
public class innerclass
{
public void SetValue(testclass target,int iValue)
{
target.val = iValue;
}
}
}
interface与class: class可以通过继承interface来实现接口. 可以隐式实现或者显式实现接口. 隐式实现即直接使用接口中的方法作为名称, 例如接口IMyInterface定义方法void Method(). public class MyClass : IMyInterface 可以通过定义/重写 void Method()来实现接口. 基类实现某接口后,子类继承时默认为以实现. 显示实现即使用 "接口名称.接口方法名称" 进行实现. public class MyClass2 : IMyInterface 中定义/重写为 void IMyInterface.Method() {...} 。隐式实现的接口可以视为类的一个属性,跟随类对象直接使用(MyClass obj=new MyClass(); obj.Method(); ) 也可以使用接口对象访问 ( MyClass obj=new MyClass(); IMyInterface myInterfaceObj=obj; myInterfaceObj.Method(); ) 但是显式实现时就只能使用接口对象访问了. ( MyClass2 obj=new MyClass2();IMyInterface myInterfaceObj=obj; myInterfaceObj.Method(); )
#region与#endregion : 这其实不应该算作语言内容,而应该算作IDE扩展. 大致意思就是可以以#region XXX开头(XXX中内容随意,一般为描述下面一大段代码的功能),以#endregion结尾的一段代码,可以被折叠起来. (讲道理C++的ifdef/endif等等也是可以被IDE折叠起来的) 不过如果代码真的需要折叠了,为什么不考虑重构呢...
partial(部分类) 这是C#与C++比较不同的地方. C++类似的大概也就是.h中定义,.cpp中实现以及Piml手法隐藏内部变量等等. C#这个partial据说是方便自动生成代码与写的代码组合在一起. 使用partial的类在编译时编译器会将所有的内容拼接在一起形成一个类. 如下:
namespace CSharpTest1
{
public partial class testclass
{
partial void DoSomethingElse();
public void DoSomething()
{
Console.WriteLine("DoSomething() started.");
DoSomethingElse();
Console.WriteLine("DoSomething() end.");
}
}
class Program
{
static void Main(string[] args)
{
testclass ts = new testclass();
ts.DoSomething();
}
}
public partial class testclass /// Part 2
{
partial void DoSomethingElse()
{
Console.WriteLine("DoSomethingElse");
}
}
}/// End of namespace CSharpTest1
其实相当于DoSomethingElse()和DoSomething()写在一起. 但是加上partial分开写也没有错.
比较令我眼前一亮的是如果将part 2 这一部分的代码去掉并不会产生编译错误,而且运行的时候也不会产生异常。要知道类似的做法(即声明一个函数而不实现却调用)在C/C++中会引起连接错误(LINK ERROR)——一种最令人头疼的错误(做跨平台的时候经常是编译什么的都过了,偏偏就是连接不上)。后来查了一下,这里编译器在编译过程中未发现DoSomethingElse()的实现于是就直接删掉了DoSomethingElse()的调用,并称此举能略微提高性能。看到这里不得不说带虚拟机的语言就是比编译型语言任性啊QwQ