普通方法中获取类名: this.GetType().Name
静态方法中获取类名: MethodBase.GetCurrentMethod().ReflectedType.Name
1.获取当前执行方法的类名:System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
2.获取当前成员的名称:MethodBase.GetCurrentMethod().Name;
log4net的使用:
1.使用Netget包管理器,添加到选定项目中来;
2.项目的AssemblyInfo.cs中添加这一行:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)]
3.创建log4net.config文件,且在文件的属性中勾选复制(到output目录)
4.使用:
4.1配置:
XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile));
ILog m_Log = LogManager.GetLogger(typeof(Debug));
4.2调用:
m_Log.InfoFormat(...)
//可自己封装Debug.
TAP编程:
Task是.NET4.0加入的,跟线程池ThreadPool的功能类似(ThreadPool相对于Thread来说可以减少线程的创建,有效减小系统开销;但是ThreadPool不能控制线程的执行顺序,我们也不能获取线程池内线程取消/异常/完成的通知,即我们不能有效监控和控制线程池中的线程。)
C#5.0引入async/await的语法糖,没有CLR的升级
C#7.1或更高版本才支持 "主异步" async Main()
C#8.0 可以使用异步流await foreach和可释放对象await using全面渗透开发的各个环节,无处不在
1.async是用来修饰方法,如果单独出现,方法会警告,没有什么作用
2.await在方法体内部,只能放在async修饰的方法内,必须放在task前面(真的吗?)
3.加了await之后,
C#和.NET及VS和Unity的版本对应关系:
C#2.0 .NET_Framework 2.0 VS2005
C#3.0 .NET_Framework 2.0/3.0/3.5 VS2008/2010
C#4.0 .NET_Framework 4.0 VS2010 Unity5.5
C#5.0 .NET_Framework 4.5 VS2012/2013
C#6.0 .NET_Framework 4.6/.NetCore1.0 VS2012/2015 Unity2017.1
C#7.0 .NET_Framework 4.6.2
C#7.1 .NET_Framework 4.7/.NetCore2.0
C#7.2 .NET_Framework 4.7.1 Unity2018.2
C#7.3 .NET_Framework 4.7.2/.NetCore2.1/2.2 Unity2018.3
C#8.0 .NET_Framework 4.8/.NetCore3.0/3.1 Unity2020.2(默认接口方法除外)
C#9.0 .NET 5.0/
VS CSharp项目 *.csproj和MSBuild:
有新旧两种语法:旧的太繁杂,新的很简洁,详见 理解 C# 项目 csproj 文件格式的本质和编译流程 - walterlv - 博客园
csproj内容解析_sgmcumt的博客-CSDN博客_csproj
Common MSBuild Project Items - MSBuild | Microsoft Docs
VS使用:
ctrl + 点两下tab键,自动完成构造函数
Nuget安装的包都在此目录下: C:\Users\lzy\.nuget\packages
Nuget的配置文件: C:\Users\lzy\AppData\Roaming\NuGet\Nuget.Config
Var, Object, dynamic:
var实际上编译器抛给我们的语法糖,一旦被编译,编译器就会自动匹配var变量的实际类型,并用实际类型来替换该变量的声明,等同于我们在编码时使用了实际类型声明。而dynamic被编译后是一个Object类型,编译器编译时不会对dynamic进行类型检查。
再说说Object,上面提到dynamic类型再编译后是一个Object类型,同样是Object类型,那么两者的区别是什么呢?
除了在编译时是否进行类型检查之外,另外一个重要的区别就是类型转化,这也是dynamic很有价值的地方,dynamic类型的实例和其他类型的实例间的转换是很简单的,开发人员能够很方便地在dyanmic和非dynamic行为间切换。任何实例都能隐式转换为dynamic类型实例
GC:Garbage Collector(垃圾收集器)
工作原理:以应用程序的root为基础,遍历应用程序在Heap(堆)上动态分配的所有对象[2],通过识别它们是否被引用来确定哪些对象是已经死亡的哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。
注:root(根):是抽象出来的一个宏观概念,就是内存中的一个单元,可看成C++里的指针,这个指针指向堆内存中的一块内存地址.
算法:为了实现这个原理,GC有多种算法; 比较常见的算法有:Reference Counting(如OC语言)、Mark Sweep(标记-清除)、 Copy Collection等等。目前主流的虚拟系统.net CLR,Java VM和Rotor都是采用的Mark Sweep算法
标记-清除是一个间接的收集算法,他本身不检测垃圾,而是确认所有存活对象,然后得出结论:其他任何对象都是垃圾(任意未被标记的对象均被视为垃圾并且回收他的空间).
0代,1代,2代,没有空间了,0代上执行GC.Collect(),实现没有空间了,抛出OutOfMemoryException.
详见:C#中Dispose,finalize,GC,析构函数区别_qq826364410的专栏-CSDN博客_c# dispose finalize
C#析构函数:和C++的类似,
一个类只能有一个析构函数;
不能被继承或重载
不能被调用,而是自动被编译器调用的
不能带修饰或参数
析构函数实际上是重写了 System.Object 中的虚方法 Finalize()
Finalize() : 属于Object的方法,引入Finalize会妨碍析构函数的调用
在System命名空间下的IDisposable接囗,提供了释放非托管资源的一种机制,只有一个方法void Dispose(), 此方法中一般都包含GC.SuppressFinalize(this)方法,这个方法会告知系统这个类已经不再需要析构了,这样可以提高释放资源的效率
非托管资源:最常用的非托管资源类型是包装操作系统资源的对象,如:窗口句柄、文件句柄、数据库连接或网络连接;
非托管资源需要显式清除。
创建封装非托管资源的对象时,建议在公共 Dispose 方法中提供必要的代码以清理非托管资源。 通过提供Dispose 方法,对象的用户可以在使用完对象后显式释放其内存
有两种释放非托管资源的方式:
1. 使用try...catch...finally块,在finally中调用dispose方法(别忘了做非空判断..)
2. 使用using语句,它等价于try...finally
https://docs.microsoft.com/zh-cn/dotnet/api/system.idisposable.dispose?redirectedfrom=MSDN&view=net-5.0#System_IDisposable_Dispose
public class Foo: IDisposable
{
private bool m_disposed;
~Foo()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
// Release managed resources
}
// Release unmanaged resources
m_disposed = true;
}
}
}
数据精度:除小数点外,从左边最高位数起的多少位数,超出范围就有误差,不能保证
其中,float的精度只有7位,double的精度是15位(如果是负数,就各减去一位)
char : -128~127
float af = 1111111.111f; //f必须要加
float a1f = 111111.111f;
float a2f = 111111111f;
double bf = 1111111.111d; //d可加可不加
double b1f = 12345678912345.111; //12345678912345.1, double是15位有效数字
double b2f = 12345678.111d;
Console.WriteLine("af :{0}", af);
Console.WriteLine("af :{0:f11}", af);
Console.WriteLine("a1f:{0}", a1f);
Console.WriteLine("a2f:{0}", a2f); //1.111111E+08 ->即 111111100
Console.WriteLine("bf :{0}", bf);
Console.WriteLine("b1f:{0:f20}", b1f);
Console.WriteLine("b2f:{0:f20}", b2f);
1. 构造函数后+ :base(), 表先执行父类的构造函数,再执行自己的
2. ?? 运算符的左操作数非 null,该运算符将返回左操作数,否则返回右操作数
3.C#的new关键字的三种用法
1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。
2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。
3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。
C#中new的两种用法public new 和new public: 在变量上 new要写在public前面,方法上 new写在public 后面
public new void Method(){...} //派生类方法定义时,在修饰符public加上new,显式地屏蔽基类方法,此时编译器将不会报warning
new public class NestedC{...} //嵌套类隐藏了基类中同名的类
where限定符:
class A<T> where T:class,new() //约束泛型必须是引用类型,必须有一个无参构造
where T: class // T必须是一个类(class)类型,不是结构(structure)类型
where T: new() // T必须要有一个无参构造函数
where T: struct // T必须是一个结构类型
where T: NameOfBaseClass // T必须继承名为NameOfBaseClass的类
where T: NameOfInterface // T必须实现名为NameOfInterface的接口
字符串类型:
string : 是不可改变对象; //要频繁的修改字符串,建议使用stringBuffer或stringBuilder
StringBuffer : 线程安全的
StringBuilder: 速度更快,但非线程安全,适合单线程下使用
string s1 = "test";
s1 += "ceshi"; //创建一个新的字符串实例,分配足够内存,先存入“test”,再存入“ceshi”,然后更新s1变量中的内存地址,使s1指向新的字符串对象,旧字符串对象将被销毁
byte与int的转换:
int s = 100;
//Int 到 Byte数组
byte[] shi = System.BitConverter.GetBytes(s);
//Byte数组到Int
int sh = System.BitConverter.ToInt32(shi,0);
容易混淆的几种运算符: ? 、?:、?? 、?.
1. 可空类型修饰符(?):
引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空。
例如:string str=null; 是正确的,int i=null; 编译器就会报错。
为了使值类型也可为空,就可以使用可空类型,即用可空类型修饰符"?"来表示,表现形式为"T?"
例如:int? 表示可空的整形,DateTime? 表示可为空的时间。
T? 其实是System.Nullable(泛型结构)的缩写形式,也就意味着当你用到T?时编译器编译 时会把T?编译成System.Nullable的形式。
例如:int?,编译后便是System.Nullable的形式。
2. 三元(运算符)表达式(?:) :
例如:x?y:z 表示如果表达式x为true,则返回y;如果x为false,则返回z,是省略if{}else{}的简单形式。
3. 空合并运算符(??) :
用于定义可空类型和引用类型的默认值。如果此运算符的左操作数不为null,则此运算符将返回左操作数,否则返回右操作数。
例如:a??b 当a为null时则返回b,a不为null时则返回a本身。
空合并运算符为右结合运算符,即操作时从右向左进行组合的。如,“a??b??c”的形式按“a??(b??c)”计算。
4、?.不为null时执行后面的操作
对象初始化器:在实例化对象时为对象的属性进行赋值,如
Person p = new Person{Name="张三",Age=28};
与构造方法的的区别如下:
相同点:都是可以对对象的属性值进行初始化赋值
不同点:
1)构造方法有强制性,方法参数必须赋值;对象初始化器没有强制性,其中属性可赋可不赋
2)对象初始化器只能对public的属性进行初始化,而构造方法可以对对象任意成员进行初始化
3)对象初始化器在创建对象的时候使用,构造方法是写在类里面的
4)构造方法.NET版本就有,对象初始化器只能在.NET3.0以上版本使用
5)使用对象初始化器对象必须有一个无参的构造方法,否则编译时就报错;构造方法只要有就行
字段:
属性: 含有get,set块,可以只有其中之一或都有。
可以简写成public string Name{get;set},这样编译器就会生成小写的字段name.
属性的应用:通过在设置值的时候做一些校验工作。
匿名类型: var i = 100; //匿名类型被赋值后,类型就确定了,不能再改变类型。
虚方法:用于给子类重写的。注:父类的也可调用。
隐藏方法:如果没用virtual和override,子类和父类有同名方法,可通过在子类中使用new关键字隐藏父类的方法,不用new也可以的。
//注:隐藏只是子类中看不到,实际还是存在的;而重写是不存在了的。样例:父类声明,子类构造,调用方法时,调的是父类的方法。
this: 当前对象的所有字段、方法、属性,包括它继承的父对象的所有字段、方法、属性;有没有this都可以访问,有只是可通过IDE的提示方便输入。
base: 父类对象的所有public方法和字段,有没有base都可以访问的,只是IDE的提示更方便
abstract : 用于把类和函数声明为抽象的。抽象类不能实例化,可以包含普通的函数和抽象的函数
抽象函数:只有函数定义(/函数签名),没有函数体。
//类是一个模板,那么抽象类就是一个不完整的模板,我们不能使用不完整的模板支构造对象
//当一个类中存在抽象方法时,这个类也必须声明为抽象类
sealed: 用于修饰类和方法,形成密封类和密封方法:
密封类 : 表示类不能被继承
密封方法 : 表示方法不能被重载(注:父类必须是virtual,子类(即自己)必须与override一起使用)
//什么时候使用: 用于防止重写某些类导致代码混乱, 和出于商业原因
接囗interface
一般情况下,接口只能包含方法,属性,索引器和事件的声明。
接口不能有构造函数,也不能有字段,接口也不允许运算符重载。
接口里面定义的函数签名不允许含有声明成员的修饰符,因为接口成员默认都是public
接囗可以继承接囗
const 编译期,总是静态的
readonly 运行期,可实例字段,也可以是静态字段
readlonly关键字:可修饰的地方:类的字段声明、struct
类型定义 、在结构类型内的实例成员声明、ref readonly 方法返回
用在类的字段声明中: 指示只能在声明期间或在同一个类的构造函数中向字段赋值。 可以在字段声明和构造函数中多次分配和重新分配只读字段。
委托:类型安全的,类似于类,常用于函数回调
内置的委托:Action<T>无返回值, Func<T>有返回值
多播委托:+=、-=语法;如有返回值,则最终输出是最后一个委托的返回值;其中一个有异常,后面的就会中断不执行了
匿名函数 : 不想再次使用的,没有名字的函数
Lamberda表达式 : 也是一个函数,C#3.0或以上才支持,可以访问外部变量,但会变得不安全
事件:基于委托,为委托提供发布/订阅的机制,是一种具有特殊签名的委托
事件的声明,只能放在类里面,不能在方法里。声明时只需在delegate前面加个event.
特性:
.Net预定义的特性
Obsolete
Conditional:只有定义了括号里的宏,才调用此特性修饰的方法;//可用于过滤debug信息的编译
.....
Assembly对象 : 程序集对象
1.class对象.Assembly
2.Assembly.Load
3.Assembly.LoadFrom()
泛型:
泛型类: 就是定义一个类,这个类中某些字段的类型是不确定的,这些类型在类构造时才确定下来:
public class ClassA<T>{
private T a;
}
泛型方法: 就是定义一个方法,这个方法的参数的类型可以是不确定的,当调用这个方法时再确定参数的类型:
public string GetSum<T>(T a,T b){...}
C#扩展已有类的方法有:1. 使用静态类的静态方法; 2.使用partial类这样的设计模式(编译时组合起来的)
作用:为现有对象添加新的行为而无需修改原有类型,是一种无侵入且非常安全的方式。
要求和使用说明:
扩展类必须是静态类,扩展方法也为静态方法
此方法的第一个参数指定方法所操作的类型;此参数前面必须加上 this 修饰符
在调用代码中,如何不在同一个命名空间,需要添加 using 指令,导入需要调用的扩展方法所在的命名空间
需要注意的是,第一个this标记的参数并非是实参,而是标识该扩展所指定的类型,调用的时候只需要提供this后的形参即可
底层: 定义采用静态方法语法,调用采用实例方法语法,中间语言 (IL) 还是当静态方法处理。
至于this,就是为了表示这是个扩展方法(与静态类的静态方法区别开来而尔):
public static class StringExendtion
{
public static int ToInt32(this string str)
{
.....
}
}
static void Main(string[] args)
{
Console.WriteLine("2".ToInt32()));
}
导包时使用using指令和using static指令的区别:
using static : 只支持静态方法和属性;
如using static System.Console; 在之后就可直接使用静态方法Write(....); WriteLine(...);
using : 用于它所在的整个文件(或命名空间),而非仅作用于静态成员
内部类 :只能直接访问外部类的静态成员若要访问非静态成员则需要实例化外部类
class和Struct的区别 : 1.不能被继承,但可实现接囗;2.引用/值类型 -> 影响存放和传参
struct不能被继承,但能实现接囗,且声明的类型不同,存放位置也不一样:
//当我们声明对象(s1、s2)是结构体类型时,对象是值类型,对象在栈中创建
//当我们声明对象(ic1、ic2)是接口类型时,对象是引用类型,对象在堆中创建
函数传参:当传递的是对象/class类型时,传递的是对象的引用,
在不改变引用的指向时,函数内部通过引用来改变(传参)对象的属性值,会影响到对象的真正的值;
1.在函数内不改变传参的对象的指向的情况下,通过参数对象.属性来修改外部对象,结果生效!
static void Main(string[] args)
{
//测试传参:传的是class对象
TestClass objA = new TestClass();
objA.Name = "I am ObjA";
Console.WriteLine($"In Main:{objA.Name}");
TestFun(objA);
Console.WriteLine($"In Main:{objA.Name}");
Console.Read();
}
static void TestFun(TestClass obj) //传递的是对象objA的引用
{
obj.Name = "I am be modified in TestFun";
Console.WriteLine($"In TestFun:{obj.Name}");
}
public class TestClass //内部类
{
public string Name { get; set; }
}
2.如果在函数内改变了引用的指向,函数内部通过引用来改变(传参)对象的属性值,这是引用其实是拷贝一份对象 a的地址,在函数内临时生效,退出时的临时
临时变量回收,所以修改不到外部的对象的属性,因为指向已经变化了:
static void Main(string[] args)
{
//测试传参:传的是class对象
TestClass objA = new TestClass();
objA.Name = "I am ObjA";
Console.WriteLine($"In Main:{objA.Name}");
TestFun(objA);
Console.WriteLine($"In Main:{objA.Name}");
//更深入传参,参考https://www.cnblogs.com/hwh_/archive/2010/11/16/1878341.html
Console.Read();
}
static void TestFun(TestClass obj) //当调用传参时,stack中拷贝一份objA的地址副本
{
TestClass objB = new TestClass();
obj = objB;
obj.Name = "I am ObjB";
Console.WriteLine($"In TestFun{obj.Name}");
}
public class TestClass
{
public string Name { get; set; }
}
C# volatile 与 lock:
编译器在优化代码时,可能会把经常用到的代码存在Cache里面,然后下一次调用就直接读取Cache而不是内存,这样就大大提高了效率。但也会带来多线程不同步的bug。
volatile : 易变的,不稳定的;volatile修饰的变量,告诉编译器不允许线程进行本地缓存,每个线程的读写都是直接操作在共享内存上,这就保证了变量始终具有一致性。缺点很明显:牺牲了效率。
volatile的使用场景:多个线程同时访问一个变量,CLR为了效率,允许每个线程进行本地缓存,这就导致了变量的不一致性。 volatile就是为了解决这个问题,
lock的使用场景:多个线程同时访问一个代码块,使用lock 修饰该代码块,强制多个线程进行排队,一个接一个的去访问。缺点很明显:排队进行必然导致效率低。
线程:缺省状态下是MTA的
.NET支持两种线程模型:STA(single threaded apartments) 和 MTA(multi threaded apartments) ,详见。
创建方式 :1.手动明确的创建; 2.利用.net framework的特性来创建线程,如后台工作线程、线程池、线程计数器、 Remoting服务器、一个网络服务器;一个ASP.NET服务器
线程属性决定了线程的执行时间,这里说的是多线程,且跟同一应用中其他活动线程相关的,级别有
enum ThreadPriority{Lowest, BelowNormal, Normal, AboveNormal, Highest}
多线程时,把线程属性设置的高并不意味着它能够实时工作,它还受应用程序的程序属性限制,所以
需要把Process设置成最高配置属性(Realtime):Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
常用方法:
t.Abort();//终止这个t线程的执行
Thread.Sleep(0);//放弃CPU的时间片,停止对CPU的占用,以使其他在时间片队中活动的线程被执行
Thread.Sleep(1000); //线程停止1000毫秒
Thread.Sleep(TimeSpan.FromHours(1)); //停止1小时
Thread.Sleep(Timeout.Infinite); //线程停止到被打断
t.Join(); //让当前线程睡眠,等待t线程执行完,然后继续运行下面的代码
EventWaitHandle : 表示一个线程同步事件
Reset() :将事件状态设置为非终止,从而导致线程受阻。
Set() :将事件状态设置为有信号,从而允许一个或多个等待线程继续执行。
WaitOne(): 阻止当前线程,直到当前 WaitHandle 收到信号。
AutoResetEvent : 继承于EventWaitHandle,表示线程同步事件在一个等待线程释放后收到信号时自动重置
WaitCallback : Represents a callback method to be executed by a ThreadPool thread
定义; public delegate void WaitCallback(objec
Mutex : 线程间同步的基元(primitive),也可用于进程间的同步。
public sealed class Mutex : System.Threading.WaitHandle
Metux只能在.Net 4.x上才能使用。 .Net2.0不支持!Metux可用在进程间的互斥锁控制,如实现只能启动一个进程。
.net托管代码和非托管代码:
托管代码:在运行时(CLR)控制下执行的代码称为托管代码;
通过高级语言(C#,VB,F#等)相应的编译器将其编译为中间语言(IL),CLR将其编译成机器代码,然后执行。托管代码可以通过 GC垃圾回收机制进行内存的管理和释放。
非托管代码 : 在运行时以外运行的代码成为非托管代码。如:COM组件、ActiveX接口和Win32 API函数都是非托管代码的示例。非托管代码需要手动释放资源。
自动内存管理和垃圾回收(COM 使用引用计数,而 CLR 使用标记清除)
反射:使用using System.Reflection;命名空间
//Type:表示类型声明(类型的元数据类),如类类型、接囗类型,数组,值类型,枚举类型,类型参数,泛型等;
//C#中通过typeof来返回一个Type对象
Type t = typeof(String);
MethodInfo substr = t.GetMethod("Substring", new Type[]{typeof(int), typeof(int)});
Object result = substr.Invoke("Hello World!", new Object[]{7,5});
Console.WriteLine("{0} returned \"{1}\".", substr, result);
//因为Object.GetType()方法返回一个Type对象,所以所有类型的一个实例都可调用此方法
object[] values = {"world", true, 120, 136.23, 'a'};
foreach(var value in values)
{
Console.WriteLine("{0} - type {1}",value, value.GetType().Name);
}
DllImport : https://www.cnblogs.com/answercard/p/5038962.html
C# 代码有以下两种可以直接调用非托管代码的方法:
1.直接调用从 DLL 导出的函数。
2.调用 COM 对象上的接口方法。
对于这两种技术,都必须向 C# 编译器提供非托管函数的声明,并且还可能需要向 C# 编译器提供如何封送与非托管代码之间传递的参数和返回值的说明
[DllImport("__Internal")]
static extern xxx FuncName(xxx)
插件使用[DllImport()]将其代码链接到C#unity.
MarshalAs属性: 可放置在方法参数、方法返回值以及结构和类的字段上
注意:In 和 Out 属性可用于批注非托管方法的参数。它们与 MIDL 源文件中的 in 和 out 修饰符的工作方式类似。请注意,Out 属性与 C# 参数修饰符 out 不同。有关 In 和 Out 属性的更多信息,请参见 InAttribute 类和 OutAttribute 类。
1.返回值上设置,显式设置 puts方法返回值的封送处理:
[DllImport("msvcrt.dll")]
[return : MarshalAs(UnmanagedType.I4)]
public static extern int puts( ....);
2.在参数上设置:
[DllImport("msvcrt.dll")]
public static extern int puts(
[MarshalAs(UnmanagedType.LPStr)]
string m);
///C#获取系统当前的用户名:(使用win32API的方式)
[DllImport("Wtsapi32.dll")]
protected static extern void WTSFreeMemory(IntPtr pointer);
[DllImport("Wtsapi32.dll")]
protected static extern bool WTSQuerySessionInformation
///C#给某个目录设置访问权限
string sysCurrUserName = WindowsAPI.GetCurrentUser();
int inde = sysCurrUserName.LastIndexOf('\\');
string realUsername = sysCurrUserName.Substring(inde + 1);
Debug.Log($"当前用户名: {realUsername}");
AddPathPower(fileDir, realUsername, "FullControl");
public void AddPathPower(string pathname, string username, string power)
{
DirectoryInfo dirinfo = new DirectoryInfo(pathname);
if ((dirinfo.Attributes & FileAttributes.ReadOnly) != 0)
{
dirinfo.Attributes = FileAttributes.Normal;
}
//取得访问控制列表
DirectorySecurity dirsecurity = dirinfo.GetAccessControl();
switch (power)
{
case "FullControl":
dirsecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
break;
case "ReadOnly":
dirsecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Read, AccessControlType.Allow));
break;
case "Write":
dirsecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Write, AccessControlType.Allow));
break;
case "Modify":
dirsecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Modify, AccessControlType.Allow));
break;
}
dirinfo.SetAccessControl(dirsecurity);
}