1.什么是GAC,他的作用是什么?
我的这篇文章有详细的介绍
https://www.cnblogs.com/zxtang/p/14313273.html
2.描述一个被protected interal 修饰的类成员的访问权限?
public 关键字是方法和成员的访问修饰符。公共访问public是允许的最高访问级别,对访问公共成员没有限制。protected 关键字是一个成员访问修饰符。受保护成员在它的类中可访问并且可由派生类访问。private 关键字是一个成员访问修饰符。私有访问是允许的最低访问级别。私有成员只有在声明它们的类和结构体中才是可访问的。internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的。
3.const和readOnly的区别?
const表示不变常量,也就是不能被修改,readonly表示只读的,也就是不能进行写的操作。readOnly和const都用来标识常量,常量成员是在编译时定义的,不能在运行时更改。两者的区别在于:
(1).使用const
关键字将const
声明为字段,并且必须在声明const
对其进行初始化(也就是必须声明的同时必须赋值),而readonly可以声明为只读字段时进行初始化,也可以只声明而在构造函数中进行初始化,且readonly只能初始化一次,构造后,只读字段无法更改。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 静态变量和动态变量的区别
{
public class Teacher
{
public const int A=100;//声明正确
public const int a;//声明错误,没有赋值
public readonly int B; //Readonly可以在构造函数中初始化
public readonly int C = 300;//Readonly也可以声明同时进行初始化
public Teacher()
{
B = 200;
}
}
}
(2).const不能声明为static的,因为const是隐式静态的,而readonly可以是静态的也可以是实例的,r实例成员,所以不同的实例有不同的常量值,readonly更灵活。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 静态变量和动态变量的区别
{
public class Student
{
private static const int A = 100;//const不能用static修饰
private readonly int B = 100;//readonly可以用static修饰
}
}
(3).const字段是编译时常量,像3.14和0这样的值是编译时常量,所以声明的时候就需要赋值,readonly是运行时常量。在程序运行的时候赋值,因此可以在构造函数中赋值或者在声明的时候赋值。
(4)const既可以被声明为字段也可以在任何函数内部声明,而readonly只能被声明为字段。
4.解释System.String和System.Text.StringBuilder的区别?
String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,也就是说对String对象进行修改需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。
StringBuilder类并没有String类的功能强大,只提供基本的替换和添加和删除字符串中的文本,但它的工作效率非常高,当定义StringBuilder对象时可以指定内存的内存容量,如果不指定系统就会根据对象初始化时的字符串长度来确定。它有两个主要参数Length和Capacity分别表示字符串的实际长度和字符串占据的内存空间长度。对字符串的修改就是在这个内存中进行的,大大提高了添加和替换的的效率。
StringBuilder sb=new StringBuilder("Hello,Welcome",100);//初始化对象并设置初始容量为100
sb.Append(" to www.csdn.net");
sb.Replace(old,new);//将old替换为new,作用与String.Replace()一样只是不需要在过程中复制字符。
StringBuilder的成员:
StringBuilder sb=new StringBuilder("Hello World") 定义初值为Hello World的值
StringBuilder
sb=new
StringBuilder(20); 初始化容量为20的空对象。另外StringBuilder还有MaxCapacity属性用来限定对象可以使用的最大容量。默认大约是int.MaxValue(20亿)可以在使用过程中定义sb.MaxCapacity=value;sb.Append(),给当前字符串追加字符串。
sb.AppendFormat()——添加特定格式的字符串
sb.Insert()——插入一个子字符串
sb.Remove()——从当前字符串删除字符
sb.Replace()——替换字符串中指定的字符
sb.ToString()——将sb转化为String 对象
5.什么是弱类型编程语言?var修饰的数据变量是强类型还是弱类型?
强类型语言也称为强类型定义语言。是一种总是强制类型定义的语言,要求变量的使用要严格符合定义,所有变量都必须先定义后使用。
ava、C#、C++等都是强制类型定义的。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。
例如你有一个整数,如果不显式地进行转换,你不能将其视为一个字符串。
与其相对应的是弱类型语言:数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。
弱类型语言也称为弱类型定义语言。与强类型定义相反。像js,php等就属于弱类型语言。
var修饰的数据变量是弱类型。
6.描述var,onject和dynamic的区别是什么?
首先三者都能够对声明的变量赋任何类型的值,var声明的变量在赋值的那一刻就决定了它是什么类型,所有的类型都派生自object. 所以它可以赋值为任何类型,dynamic不是在编译时候确定实际类型的, 而是在运行时。
var是C# 3中引入的,其实它仅仅只是一个语法. var本身并不是 一种类型, 其它两者object和dynamic是类型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VarObjectDynamic
{
class Program
{
static void Main(string[] args)
{
var a = 10;//var声明的变量在赋值的那一刻就决定了它是什么类型
object b = 20;//所有的类型都派生自object. 所以它可以赋值为任何类型
dynamic c = "hello";//dynamic不是在编译时候确定实际类型的, 而是在运行时。
//所以下面的代码是能够通过编译的,但是会在运行时报错
c++;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
}
}
}
7.值类型和引用类型的区别是什么?
在C#中值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中。
常见的值类型包括:byte,short,int,long,float,double,decimal,char,bool 和 struct ,值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
引用类型:class(类),string,interface(接口),delegate(委托)。当声明一个类时,只在栈中分配一小片内存用于容纳一个地址(等new实例后堆上的地址将保存到该空间),而此时并没有为其分配堆上的内存空间。当
使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。引用类型的对象总是在进
程堆中分配(动态分配)。
盗用一下大佬的图
值类型:
引用类型:@为存放的堆空间的地址
引用类型和值类型相同点:
(1)引用类型可以实现接口,值类型当中的结构体也可以实现接口;
(2)引用类型和值类型都继承自System.Object类。
范围方面
(1)C#的值类型包括:结构体(数值类型、bool型、用户定义的结构体),枚举,可空类型。
(2)C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。
内存分配方面:
(1)数组的元素不管是引用类型还是值类型,都存储在托管堆上。
(2)引用类型在栈中存储一个引用,其实际的存储位置位于托管堆。简称引用类型部署在托管推上。而值类型总是分配在它声明的地方:作为字段时,跟随其所属的变量(实例)存储;作为局部变量时,存储在栈上。
(栈的内存是自动释放的,堆内存是在NET中会由GC来自动释放)
适用场合
(1)值类型在内存管理方面具有更好的效率,并且不支持多态,适合用做存储数据的载体;引用类型支持多态,适合用于定义应用程序的行为。
值得注意的是,引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即直接继承System.ValueType。即System.ValueType本身是一个类类
型,而不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。
8.Ref和out修饰的参数分别代表什么意思?
ref 关键字使参数按引用传递。其效果是,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化,而out是要把参数清空,就是说你无法把一个数值从out传递进去,out进去后,参数的数值为空,所以离
开当前方法前必须对out修饰的变量赋一次值。若要使用 out 参数,方法定义和调用方法都必须显式使用out 关键字。
如上所示,使用ref传递参数,参数必须要初始化。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ref和out
{
class Program
{
static void Main(string[] args)
{
int b=1;
Method1(ref b);
Console.WriteLine("b="+b);//输出100
int c;
Method2(out c);
Console.WriteLine("c="+c);//输出200
Console.ReadLine();
}
static void Method1(ref int a)
{
a = 100;
}
static void Method2(out int a)
{
a = 300;//必须在离开方法前对a赋值,否则回报错
}
}
}
9.什么是后期绑定或者晚期绑定,如何实现后期绑定?
后期绑定又可以称为动态绑定(dynamic binding),需要使用System.Reflection,动态地获取程序集里封装的方法、属性等。这种后期绑定的方法大量的被使用在IDE和UI设计中,后期绑定的优点是可
以保存对任何对象的引用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Binding
{
class Program
{
static void Main(string[] args)
{
Type _type = Type.GetType("Binding.Employee");
Console.WriteLine(_type.FullName);
Console.WriteLine(_type.Namespace);
Console.WriteLine(_type.Name);
Console.WriteLine("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*程序集中的所有信息集合\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*");
Console.WriteLine("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*程序集中的所有属性信息\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*");
PropertyInfo\[\] info = \_type.GetProperties();//获取属性信息
foreach (PropertyInfo propinfo in info)
{
Console.WriteLine(propinfo.Name);
}
Console.WriteLine("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*程序集中的所有方法信息\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*");
MethodInfo\[\] methods = \_type.GetMethods();//获取方法
foreach (MethodInfo methodinfo in methods)
{
Console.WriteLine(methodinfo.Name+""+"\\t"+methodinfo.ReturnType.Name);//获取此方法名和方法返回类型
}
Console.Read();
}
}
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public float Salary { get; set; }
public Employee()
{
ID = -1;
Name = string.Empty;
Salary = 0;
}
public Employee(int id, string name, float salary)
{
ID = id;
Name = name;
Salary = salary;
}
}
}
输出结果为:
Binding.Employee
Binding
Employee
****************************程序集中的所有信息集合***************************
****************************程序集中的所有属性信息***************************
ID
Name
Salary
****************************程序集中的所有方法信息***************************
get_ID Int32
set_ID Void
get_Name String
set_Name Void
get_Salary Single
set_Salary Void
Equals Boolean
GetHashCode Int32
GetType Type
ToString String
每个属性都有set和get方法
10.描述一下new关键字的三种用法?
在 C# 中,new 关键字可用作运算符、修饰符或约束。
1)new 运算符:用于创建对象和调用构造函数。
2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。
3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。
第一种用法就不介绍了,下面介绍第二种和第三种用法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace new关键字三种用法
{
//用法2
public class Father
{
public string Name { get; set; }
public int Age { get; set; }
public int Height { get; set; }
public string Job { get; set; }
public void Talk()
{
Console.WriteLine("Father is talking");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace new关键字三种用法
{
public class Son:Father
{
new public string Job { get; set; }//隐藏和基类中的同名属性
new public void Talk() //隐藏和基类中的同名方法
{
Console.WriteLine("Son is talking");
}
}
}
用法3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace new关键字三种用法
{
public class Teacher
{
//如果有了有参构造函数,那么无参构造函数要显示的写出来,如果没有有参构造函数,系统会默认有无参构造函数,无参构造函数可写可不写
public Teacher()
{
}
public Teacher(string name)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace new关键字三种用法
{
class Program
{
static void Main(string[] args)
{
MyClass
myClass.test1();
Console.ReadLine();
}
}
//使用new关键字修饰的T必须要有无参构造函数
class MyClass<T> where T : new()
{
public void test1()
{
Console.WriteLine("哈哈");
}
}
}
11.描述一下接口和基类的区别,定义接口的目的是什么?
使用接口和基类都可以实现多态:
(1)通过继承实现多态,基类类型作为方法的返回值类型,实际上返回的是一个具体的子类对象;基类类型作为方法参数类型实际上传递的是具体的子类对象。
(2)接口实现多态,接口作为方法返回值类型,实际上返回的是一个接口实现类对象;接口类型作为方法参数类型实际上传递的是一个接口实现类对象。
当开发一个软件的时候,可能很多时候设计完一个对象之后,并不需要马上考虑或者不知道这个对象具体怎样编写,只知道他要干什么,但不知道怎么实现,还有一种情况就是团队开发,比如一个项目
设计分为10个模块,10个小组完成,怎么做到各自开发各的模块呢?这时候使用接口就可以解决。接口只有方法规定,但是没有方法的具体实现。
通常实现多态要么通过抽象类。要么通过接口,都遵循里氏替换原则,即父类出现的地方可以使用子类替换。抽象类和接口的区别:
(1)接口侧重的是功能的封装,抽象类侧重的是代码的复用和继承,通常把公共行为放到基类中,然后需要多态的行为放到接口中。
(2)接口更简洁,使用更方便,框架设计中,使用的大都是接口而不是抽象类。
下面见一个例子,具体说明了通过继承实现多态和接口实现多态:
例子1:通过继承实现多态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InherianceAndPolymoriphism2
{
abstract class Person
{
//公共属性
public string Name { get; set; }
public string Id { get; set; }
public DateTime DateofBirth { get; set; }
//protected只能供子类使用,也就是只能在子类内部使用,不能通过子类对象去使用
protected string PhoenNumber { get; set; }
//构造方法
public Person() { }
public Person(string Name,string Id) {
this.Name = Name;
this.Id = Id;
}
//共同的行为:可以放在父类中
public void Dowork1()
{
Console.WriteLine($"【调用父类的公共方法】:{Name}正在工作");
}
public void Dowork2() {
Console.WriteLine($"【调用父类的公共方法】:{Name}正在写作");
}
//父类私有的成员
private void PersonDoWork()
{
Console.WriteLine($"{Name}正在泡妞");
}
//抽象方法:父类规范一个行为要求(没有方法体),具体实现由子类来实现,具有强制性,即子类必须要实现该行为
//抽象方法只能包含在抽象类中,但是抽象类可以不包含抽象方法,且抽象类不能通过new构造
public abstract void Have();
//虚方法:父类可以对该方法有实现,子类也可以对该方法进行重写,不具有强制性,即子类也可以对该方法不进行重写
public virtual void Sleep()
{
Console.WriteLine($"【父类实现的虚方法】:{Name}正在睡觉");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
public class Student:Person
{
//属性
public int StudentId { get; set; }
public string ClassName { get; set; }
//构造方法
public Student() { }
public Student(string name, string id, string ClassName, int StudentId) : base(name, id)
{
//base.Name = name;
//base.Id = id; //或者这样继承,不过上述继承参数的方式写比较简便
this.ClassName = ClassName;
this.StudentId = StudentId;
}
//实现抽象类方法:关键字为override,必须实现
public override void Have()
{
Console.WriteLine($"【Student子类实现父类中的抽象方法】:{Name}正在吃饭");
}
//重写虚方法,关键字为override
//父类中的虚方法不调用,除非子类主动调用base.Sleep(),父类中的虚方法既可以在父类中实现,也可以在子类中进行重写,或者两者都不实现
public override void Sleep()
{
Console.WriteLine($"【Student子类重写父类中的虚方法】:{Name}正在睡觉");
base.Sleep();//子类调用父类的虚方法
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
class Program
{
static void Main(string[] args)
{
Student student = new Student();
Person p = new Student();//里氏替换原则
//父类作为方法返回值类型,实际返回的是一个具体的子类对象;/父类作为方法参数类型,实际传递的是一个具体的子类对象
p = TestStudent(student);
Console.ReadKey();
}
private static Person TestStudent(Person p)
{
p.Name = "小唐";
//调用父类的公共方法,无法调用私有方法
p.Dowork1();
p.Dowork2();
//调用抽象方法
p.Have();
p.Sleep();
return p;
}
}
}
输出结果:
【调用父类的公共方法】:小唐正在工作
【调用父类的公共方法】:小唐正在写作
【Student子类实现父类中的抽象方法】:小唐正在吃饭
【Student子类重写父类中的虚方法】:小唐正在睡觉
【父类实现的虚方法】:小唐正在睡觉
例子2:通过接口实现多态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
abstract public class Person
{
//公共属性
public string Name { get; set; }
public string Id { get; set; }
//构造方法
public Person() { }
public Person(string Name, string Id)
{
this.Name = Name;
this.Id = Id;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
//定义演讲接口
public interface IMeeting
{
//规定行为:行为不能有方法体,且不能加public
/// <summary>
/// 演讲
/// </summary>
void Speech();
/// <summary>
/// 谈话
/// </summary>
void Talk();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
//定义教学接口
public interface ITeach
{
///
void Lecture();
/// <summary>
/// 教学研究
/// </summary>
void StudyCourse();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
public class Teacher : Person, ITeach
{
public override void Have()
{
Console.WriteLine($"{Name}正在吃饭");
}
public void Lecture()
{
Console.WriteLine($"{Name}正在授课");
}
public void StudyCourse()
{
Console.WriteLine($"{Name}正在教学研究");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
public class President : Person,IMeeting
{
//实现抽象类方法
public override void Have()
{
Console.WriteLine($"{Name}正在吃饭");
}
//实现接口
public void Speech()
{
Console.WriteLine($"{Name}正在演讲");
}
//实现接口
public void Talk()
{
Console.WriteLine($"{Name}正在谈话");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 继承和多态
{
class Program
{
static void Main(string[] args)
{
//里氏替换原则
IMeeting meeting1 = new President() { Name = "唐主任" };
ITeach teach1 = new Teacher() { Name = "唐老师" };
TestIMeeting(meeting1);
TestITeach(teach1);
meeting1.Speech();
teach1.Lecture();
Console.ReadKey();
}
//接口实现多态方式一:接口作为方法参数类型,实际传递的是接口的实现类对象President
private static IMeeting TestIMeeting(IMeeting meeting)
{
//接口实现多态方式二:接口作为方法返回值类型,实际返回的是接口的实现类对象President
return new President();
}
//接口实现多态方式一:接口作为方法参数类型,实际传递的是接口的实现类对象Teacher
private static ITeach TestITeach(ITeach teach)
{
//接口实现多态方式二:接口作为方法返回值类型,实际返回的是接口的实现类对象Teacher
return new Teacher();
}
}
}
输出结果:
唐主任正在演讲
唐老师正在授课
12.什么是委托,委托和事件的关系是什么?
委托是一种程序特性,委托可代表一个或者多个同类型的方法,简单的说委托就是方法的变量,能够代表方法。委托的使用步骤如下:
【1】声明委托,定义一个方法的“样子”,也就是我们说的原型,就是指方法的返回值类型、方法的参数类型和个数。
【2】根据委托编写具体的方法
【3】创建委托变量
【4】委托变量关联具体方法(多路委托,使用+=关联多个方法,调用委托的时候将会按顺序执行各个方法)
【5】调用委托
委托的应用:当你在对象之间传递数据的时候,普通方法根本搞不定,这时候使用委托一定能够搞定,主要用在跨线程访问中,例如:
正常情况下:在A对象中创建了B对象,这时候如果B对象中有一个公共行为C,那么在A中是可以调用的
class A
{
B b=new B();
void MyMethod()
{
b.C();
}
void NewMethod()
{
}
}
问题是如果想在B中调用A中的行为NewMethod是否可以?当然不行!但是通过委托是可以的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
public class A
{
B b = new B();
public void MyMethod()
{
b.C();
//【4】将委托变量关联具体方法
b.newMethodDelegate += NewMethod;
//通过委托实现b调用A中的方法NewMethod
b.B_NewMethod();
}
void NewMethod()
{
Console.WriteLine("执行A中的NewMethod方法");
}
}
//【1】声明委托
public delegate void NewMethodDelegate();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
public class B
{
//【3】创建委托变量
public NewMethodDelegate newMethodDelegate ;
public void C()
{
Console.WriteLine("执行B中的C方法");
}
//【5】调用委托
public void B_NewMethod()
{
newMethodDelegate();
}
}
}
输出结果:
执行B中的C方法
执行A中的NewMethod方法
事件概念:事件其实是对象对外界信息的刺激,产生的一种消息响应机制。本质上事件其实是委托的进一步包装。
随便选取一个按钮事件做例子:
【1】声明委托
public delegate void EventHandler(object sender, EventArgs e);
【2】定义一个委托事件
public event EventHandler Click;
【3】关联委托
this.btn_Login.Click += new System.EventHandler(this.btn_Login_Click);//将事件和方法关联
事件和委托对比不同点:
第一、事件无法直接赋值,比如事件=null;会出现编译错误,而委托可以。
好处:避免用户对事件直接操作,比如Click事件,如果允许Click=null,会把底层代码清除!可以起到保护。
委托相对太“开放”。
第二、event对象没有invoke()方法,只能通过使用括号的方式来运行。
委托和事件的选择:
第一、正常解决问题,你使用委托和事件没有什么本质区别。所以,我们建议是使用委托。
第二、如果我们做控件二次开发,扩展控件的事件的时候,那必须用事件。
13.描述一下创建并启动一个线程的基本过程?
14什么是序列化,序列化常用的三种格式是什么?
如果我们给自己写的类标识[Serializable]特性,我们就能将这些类序列化。除非类的成员标记了[NonSerializable],序列化会将类中的所有成员都序列化。
(1)BinaryFormatter序列化:将对象序列化二进制流格式。
(2)SoapFormatter序列化:SOAP是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传 输协议(HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。SOAP序列化的主要优势在于可移植性。SoapFormatter把对象序列化成SOAP消息或解析SOAP消息并重构被序 列化的对象。
(3)XML序列化方式:将对象序列化为XML文件。
15.Trace和Debug类的作用是什么,二者有什么区别?
在 C# 语言中允许使用Trace和Debug类输出程序运行时的调试信息,类似于使用 Console.WriteLine 的方式向控制台输出信息。
所谓调试信息是程序员在程序运行时需要获取的程序运行的过程,以便程序员更好地解决程序中出现的问题,这种调试也被称为是非中断调试。
需要注意的是当程序在 Debug 状态下执行时使用 Debug 类和Trace类均可以在输出窗口中显示输出信息,而在 Release 状态下执行时只有 Trace 类输出的内容才会显示在输出窗口中。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Trace和Debug
{
class Program
{
static void Main(string[] args)
{
Trace.WriteLine("Trace");
Debug.WriteLine("Debug");
Console.ReadKey();
}
}
}
Debug调试状态下的输出:
Release状态下的调试输出:
16WCF框架解决的是什么问题?
17.WCF中的ABC分别指的是什么?
18.描述WCF中三种服务实例上下文模式?
19.WPF绑定数据的4种模式?
20.什么是依赖属性,其作用是什么?
21.什么是逻辑树?可视树?他们和默认模板的关系是什么?
手机扫一扫
移动阅读更方便
你可能感兴趣的文章