1、一个类必须声明为public才能被别的项目(程序集)访问,不写或者写internal,那么这个类就不能被别的项目访问,只有当前程序集内部可以访问。
二:索引器没有名字,索引器的内部本质(ILSpy的IL模式下看)类型 this[参数]{get;set;}
可以是只读或者只写(在get或者set前加上private)
字符串是只读索引,因此不能对字符串中的某个字符进行从新赋值,即只能char ch = s[5];不能s[5]=‘a’。
开发中自己写的机会很少,一道面试题:C#中索引器是否只能根据数字进行索引?是否允许多个索引器参数?答案:可以进行非数字索引,可以允许多个参数进行索引。
internal class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1[3, 5] = "hello";
string s = p1[1, 2];
//Dictionary d = new Dictionary();
//d[3] = "";
Console.WriteLine(s);
Console.ReadLine();
}
}
class Person
{
public string this[int x, int y]
{
get
{
return "" + x + y;
}
set
{
Console.WriteLine("x = " + x + "; y = " + y + "; value = " + value);
}
}
}
三:密闭类和静态类
1、密闭类是修饰为sealed的类,sealed不能有子类。一般只有系统中的一些基本类声明为sealed。面试题:是否可以编写一个类继承自String类?
答:不能,因为string被声明为了sealed了。
2、静态类:声明为static的类,不能实例化,只能定义static成员。通常用作定义扩展方法。
3、C#3.0特性:扩展方法。声明静态类,增加一个静态方法,第一个参数是被扩展类型的标记为this,然后在其他类中可以直接调用,本质上还是对静态方法调用提供的一个“语法糖”,也可以用普通静态方法的方式调用,所以不能访问private和protected成员。例子:给String扩展一个IsEmail方法。自己写的机会比较少。
internal class Program
{
static void Main(string[] args)
{
//string e = "abc@163.com";
//bool b = Person.IsEmail(e);
//bool b = e.IsEmail();
string s1 = "abcd";
string s2 = s1.Repeat(3);
Console.WriteLine(s2);
Console.ReadLine();
}
}
static class Person
{
//扩展方法
public static bool IsEmail(this string s)
{
return s.Contains("@");
}
public static string Repeat(this string s, int count)
{
string result = "";
for (int i = 0; i < count; i++)
{
result += s;
}
return result;
}
//public static bool IsEmail(string s)
//{
// return s.Contains("@");
//}
}
四:深拷贝、浅拷贝
如果拷贝的时候共享被引用的对象就是浅拷贝,如果被引用的对象也拷贝一份出来就是深拷贝。(深拷贝就是说重新new一个对象,然后把之前的那个对象的属性值在重新赋值给这个用户)。
internal class Program
{
static void Main(string[] args)
{
//Person p1 = new Person();
//p1.Name = "lilei";
//p1.Age = 10;
//Person p2 = p1; //让p2指向p1当前所指向的对象
拷贝、克隆:Clone
//Person p3 = new Person(); //拷贝了一份出来
//p3.Name = p1.Name;
//p3.Age = p1.Age;
//p1.Age = 20;
Dog dog = new Dog();
dog.Name = "wangcai";
Person p1 = new Person();
p1.Name = "lilei";
p1.Age = 10;
p1.Dog = dog;
Person p2 = new Person();
p2.Name = p1.Name;
p2.Age = p1.Age;
p2.Dog = (Dog)p1.Dog.Clone();
p1.Dog.Name = "erdan";
Console.WriteLine(p2.Dog.Name);
Console.ReadLine();
}
}
class Dog
{
public string Name { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Dog Dog { get; set; }
}
五:结构体
在平时的开发中很少自己去写结构体,是一种值类型的数据。对于结构,不像类那样存在继承,一个结构体不能从另一个结构或类继承。但是结构体从基类Object继承。
internal class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "lilei";
p1.Age = 10;
Person p2 = p1;
p1.Age = 20;
Console.WriteLine(p2.Age);
Dog d1 = new Dog();
d1.Name = "lilei";
d1.Age = 10;
Dog d2 = d1;
d1.Age = 20;
Console.WriteLine(d2.Age);
Console.ReadLine();
}
}
struct Dog
{
public string Name { get; set; }
public int Age { get; set; }
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
六:值类型和引用类型
什么是“引用类型”:引用类型派生自System.Object
什么是“值类型”:值类型均隐式派生自System.ValueType(ValueType其实也是继承自Object,不过是特立独行的一个分支)
值类型有哪些:数值类型(int、long、double、float、char)、bool、结构体、枚举。(在平时写的时候看不到Int32继承自ValueType的原因是编译器帮我们进行了处理)
引用类型有哪些字符串、数组、类、接口等
区别(主要):
引用类型变量的赋值只复制对对象的引用;引用类型在堆内存(malloc);
值类型变量赋值会拷贝一个副本;值类型在栈内存;值类型一定是sealed;
string是const引用,所以复制时,会拷贝副本,效果和值类型类似。
七:CTS、CLS、CLR1、 .Net平台下不只有C#语言,还有VB.Net、F#等语言。IL是程序最终编译的可以执行的二进制代码(托管代码),不同的语言最终都编译成标准的IL(中间语言,MSIL);这样C#可以调用VB.Net写的程序集(Assembly,dll、exe)。在.Net平台下:不同语言之间可以互联互通、互相调用。
2、不同语言中的数据类型各不相同,比如整数类型在VB.Net中是Integer、C#中是int。.Net平台规定了通用数据类型(CTS,Common Type System),各个语言编译器把自己语言的类型翻译成CTS中的类型。int是C#中的类型,Int32是CTS中的类型;int是C#的关键字,Int32不是。
面试题:
string和String的区别是什么?答:string是C#语言的中的类型,String是CTS中的类型
int和Int32的区别是什么? 答:int是C#中的类型,Int32是CTS中的数据类型
3、不同语言的语法不一样,比如定义一个类A继承自B的C#语法是class A:B{},VB.Net的语法是Class A Inherits B。.Net平台规定了通用语言规范(CLS, Common Language Specification )。
4、IL代码由公共语言运行时(CLR, Common Language Runtime )驱动运行,CLR提供了垃圾回收(GC, Garbage Collection,没有任何引用的对象可以被自动回收,分析什么时候可以被回收)、JIT(即时编译器)。
5、值类型是放在“栈内存”中,引用类型放到“堆内存”,栈内存会方法结束后自动释放,“堆内存”则需要GC来回收。
八:拆箱、装箱值类型赋值给Object类型变量的时候,会发生装箱:包装成Object。ValueType不也是继承自Object吗(CLR内部处理);
Object类型变量赋值给值类型赋值的时候会发生拆箱,需要做显式转换。
下面几句代码有没有错,解释一下内存是怎么变化的
int i=10;
object obj = i; //装箱 内存由栈内存转为堆内存
int j = obj; //错误
long j = (long)obj; //错误 拆箱的时候要和装箱时的数据类型一样
int j = (int)obj; //拆箱 内存由堆内存转为栈内存
拆箱的时候一定要用装箱的类型
九:关于相等 Equals


