C#编程解惑
1、类中静态构造函数的说明
- 静态构造函数只能执行一次;
- 静态构造函数不能有访问修饰符;
- 静态构造函数先于其他构造函数,首先被执行;
- 静态构造函数必须无参数;
2、静态构造函数直接实用类调用的时候就会被调用;当然创建实例的时候也会调用;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(MyTest.str);
Console.ReadLine();
}
}
public class MyTest
{
public static string str = "123";
static MyTest()
{
Console.WriteLine("hehe");
}
}
3、子类构造函数和父类构造函数的执行顺序问题,代码如下,eg:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 new B(); 6 Console.ReadLine(); 7 } 8 } 9 10 class A 11 { 12 public A() 13 { 14 PrintFields(); 15 } 16 public virtual void PrintFields() { } 17 } 18 class B : A 19 { 20 private int x = 1; 21 private int y; 22 public B() 23 { 24 y = -1; 25 } 26 27 public override void PrintFields() 28 { 29 Console.WriteLine("x={0},y={1}", x, y); 30 } 31 }
结果是x=1,y=0,下面讲解一下,当我们创建B类对象的时候,我们先会给B分配一块内存空间,并且初始化其中的字段,把x,y分别初始化。然后就调用B的无参构造函数,由于是继承自类A,所以这里先调用A类中的构造函数,在调用B类中的构造函数,执行A类中的构造函数就会执行B中重写的PrintFields方法,然后输出字符,接着在调用B中的构造函数为y赋值,把y赋值为-1,但是这个时候语句已经输出了,所以y=-1不会显示出来。所以结果就是x=1,y=0;如果在B类的构造函数中添加一句如下代码:
1 Console.WriteLine("x={0},y={1}", x, y);
那么构造函数中的输出结果就会变成x=1,y=-1了。
4、if(a=="")、if(a==String.Empty)、if(a.Length==0)三者之间的性能比较
if(a.Length==0)最快。
那么为什么if(a.Length==0)最快呢?
因为整数判断等于最快,没有经过实例化等复杂的过程。
5、页面之间传值有一个这个方法,Server.Transfer,这个方法性能比Response.Redirect的性能好一些。Response.Redirect请求两次,而Server.Transfer只请求一次;Response.Redirect面向的是任何网址都可以,而Server.Transfer只面对本站中的文件;Response.Redirect跳转页面的时候会改变地址栏地址而Server.Transfer不会改变地址栏地址。下面讲解一下如何使用Server.Transfer,eg:
Index主页,点击button按钮的时候跳转到其他页面
public string Name { get { return TextBox1.Text; } }//在页面添加属性方便以后页面访问此属性 protected void Button1_Click(object sender, EventArgs e) { Server.Transfer("about.aspx"); }
About页面
protected void Page_Load(object sender, EventArgs e) { _Default df = (_Default)Context.Handler; Response.Write(df.Name); }
6、一个静态类中只能有静态方法、属性、索引器等,不能有实例方法,也不可以有virtual、abstract等方法,因为静态类就是一个工具类,所以不能有上面的那些东西。
7、泛型约束条件可以有多个,class约束代表引用约束、struct代表值类型约束、new ()代表的是有一个无参构造函数的约束。代码如下,eg:
a、简单情况约束
1 interface IMyInterface<T> where T:struct,IComparable//struct 是值类型约束不是结构体,class、 struct类型约束要放在所有约束的最前面,class约束是引用类型约束
b、有多个类型参数,有多个约束的情况,eg:
1 interface IMyInterface<T, U> 2 where T : class, IComparable 3 where U : struct,ICollection<int> 4 { 5 6 }
其中T参数必须是引用类型的同时T类型的参数必须实现IComparable接口,U类型参数必须是值类型,并且必须实现ICollections<int> 这个泛型接口。
c、类型约束中的第二个参数是受第一个参数约束的情况,eg:
1 interface IMyInterface<T, U> 2 where T:IComparable 3 where U : T,new () 4 { 5 6 }
U类型参数必须继承自T类型,并且U类型必须有一个默认的构造函数。
8、Trim函数的特殊使用,Trim函数除了有去空格的作用还可以替换原有字符串中的特定字符,代码如下,eg:
1 string str = "yesbyesseyaseyys"; 2 string result = str.Trim('y', 'e', 's');//这行代码就是把str中的开头和结尾包含yes的所有字母都递归替换掉,直到没有遇到这个字符为止。 3 Console.WriteLine(result); 4 Console.ReadLine();
运行结果:“byesseya”
9、IEnumerable接口的数据和List集合数据
IEnumerable接口的数据只能通过foreach遍历而不能通过for来循环遍历;所以IEnumerable接口的数据也没法修改。但是list集合数据却可以。
10、以前比较两个对象通常会实现下面两个接口,代码如下,eg:
1 class Person :IComparer 2 { 3 public int Age { get; set; } 4 public string Name { get; set; } 5 6 public int Compare(object x, object y) 7 { 8 throw new NotImplementedException(); 9 } 10 } 11 12 class Anminal :IComparable 13 { 14 public int Age { get; set; } 15 public string Name { get; set; } 16 public int CompareTo(object obj) 17 { 18 throw new NotImplementedException(); 19 } 20 }
我们可以看到其中的方法都是object类型,几乎每一次计算的时候都得进行类型转换。这个时候我们就可以使用泛型接口了,具体代码如下,eg:
实现IComparable接口
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Person person1 = new Person(); 6 person1.Age = 20; 7 Person person2 = new Person(); 8 person2.Age = 30; 9 Person person3 = new Person(); 10 person3.Age = 15; 11 List<Person> list = new List<Person>(); 12 list.Add(person1); 13 list.Add(person2); 14 list.Add(person3); 15 foreach (var A in list) 16 { 17 Console.WriteLine(A.Age); 18 } 19 list.Sort(); 20 foreach (var A in list) 21 { 22 Console.WriteLine(A.Age); 23 } 24 Console.ReadLine(); 25 } 26 } 27 class Person : IComparable<Person> 28 { 29 public int Age { get; set; } 30 public string Name { get; set; } 31 32 public int CompareTo(Person other) 33 { 34 return this.Age - other.Age; 35 } 36 }
实现IComparer接口
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Person person1 = new Person(); 6 person1.Age = 20; 7 Person person2 = new Person(); 8 person2.Age = 30; 9 Person person3 = new Person(); 10 person3.Age = 15; 11 List<Person> list = new List<Person>(); 12 list.Add(person1); 13 list.Add(person2); 14 list.Add(person3); 15 foreach (var A in list) 16 { 17 Console.WriteLine(A.Age); 18 } 19 list.Sort(new Person());//此处参数为实现了IComparer接口的对象(也可以传递person1、person2、person3等对象)。 20 foreach (var A in list) 21 { 22 Console.WriteLine(A.Age); 23 } 24 Console.ReadLine(); 25 } 26 } 27 class Person :IComparer<Person> 28 { 29 public int Age { get; set; } 30 public string Name { get; set; } 31 32 public int Compare(Person x, Person y) 33 { 34 return x.Age - y.Age; 35 } 36 }
11、委托Action委托和Action<>是不同的两中,Action是无参无返回值的而,Action<>是有参数无返回值的委托。代码如下,eg:
1 Action action = new Action(() => { Console.WriteLine("234"); }); 2 Action<int> action1 = new Action<int>(x => { Console.WriteLine("234"); });
12、Predicate表示的是一个参数一个bool返回值,代码如下,eg:
Predicate<int> pre = new Predicate<int>(x => x == 3);
13、Func中的参数列表是最后一个参数是返回类型,其他都是输入参数,我们最多可以输入16个参数,具体代码如下,eg:
Func<int, string, string> func = new Func<int, string, string>((x, y) => x.ToString() + y);
上面代码最后一个string 是返回值类型,前两个int 和string 是输入参数。
14、Func<>和Action<>最多只能有16个输入参数。如果还是不能满足需求的话,就需要自己写了,通过上面的代码我们知道了以后基本上我们都可以不用写委托了,因为上面的三种委托已经够我们使用了。
15、老长时间没有使用WinForm的用户自定义控件,WinForm的用户自定义控件和WebForm的用户自定义控件使用上有点区别,WebForm创建完了用户自定义控件之后就可以拖拽到页面上使用而WinForm必须是先创建用户自定义控件,然后编译程序,才会在工具箱位置生成相对应的自定义控件,这个时候我们才可以去拖拽到页面上去使用。
浙公网安备 33010602011771号