在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近发现对于C#的使用水平一只停留在3.0的程度 对于4.0 5.0的新特性使用的很少,写一篇文章记录一下增加一下认识。 C# 3.5扩展方法扩展方法所在的类和扩展方法必须是静态的 并且扩展方法第一个参数是要扩展的类名 并在this Person person = new Person(); public static class Extension person.ExtensionMethod(); 当person调用 ExtensionMethod()时,C# Compiler 会把这段Source Code 编译成Static Method 的IL Code。也可以理解为 编译器做了这样的处理,person.ExtensionMethod(); => ExtensionMethod(person); C# Compiler 编译的过程是这样的:
c#4.0弱引用我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的。我们能不能同时保持对对象的引用,而又可以让GC需要的时候回收这个对象呢?.NET中提供了WeakReference来实现。弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。弱引用使用起来很简单,看下面的代码: 可选参数方法带有可选参数方法的声明: public StreamReader OpenTextFile(string path,Encoding encoding = null,bool detectEncoding = true,int bufferSize = 1024); 命名参数必须在最后使用: OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096); 顺序不限: OpenTextFile(bufferSize: 4096, path: "foo.txt", detectEncoding: false); Lazy<T>我们也许会遇到这样一种情况,我们有一个大家伙(大对象)需要创建,那么这个对象的创建时需要较长的时间,同时也需要在托管堆上分配较多的空间。 那么在.NET Framework 4 中提供了这样一个很聪明的方式:Lazy<T>(我们可以称之为懒对象)。当然,在之前,很多人也曾对其进行过自己的实现。 那么我们在这里就可以把 Lazy<T> 的作用总结为一句话,按需延迟加载。 内存映射文件<?XML:NAMESPACE PREFIX = [default] http://www.w3.org/1999/xhtml NS = "http://www.w3.org/1999/xhtml" />利用文件与内存空间之间的映射,应用程序(包括多个进程)可以通过直接在内存中进行读写来修改文件。 从 .NET Framework 4 版开始,可以使用托管代码按照本机 Windows 函数访问内存映射文件的方式来访问内存映射文件,如 MSDN Library 中的 Managing Memory-Mapped Files in Win32(管理 Win32 中的内存映射文件)中所述。 动态语言运行时4.0中增加了与编译器相关的API,这样就可以将字符串作为代码动态编译执行,跟javascript好像。借助于 DLR,可以更轻松地开发要在 .NET Framework 上运行的动态语言,而且向静态类型化语言添加动态功能也会更容易。 动态语言可以在运行时标识对象的类型,而在类似 C# 和 Visual Basic 的静态类型化语言中(当您使用 Option Explicit On 时),您必须在设计时指定对象类型。 动态语言的示例有:Lisp、Smalltalk、JavaScript、PHP、Ruby、Python、ColdFusion、Lua、Cobra 和 Groovy。 大多数动态语言都会向开发人员提供以下优点:
利用动态语言可以生成优秀的脚本语言。 利用新的命令和功能,客户可以轻松地扩展使用动态语言创建的应用程序。 动态语言还经常用于创建网站和测试工具、维护服务器场、开发各种实用工具以及执行数据转换。 DLR 的目的是允许动态语言系统在 .NET Framework 上运行,并为动态语言提供 .NET 互操作性。 在 Visual Studio 2010 中,DLR 将动态对象引入到 C# 和 Visual Basic 中,以便这些语言能够支持动态行为,并且可以与动态语言进行互操作。 DLR 还可帮助您创建支持动态操作的库。 例如,如果您具有一个使用 XML 或 JavaScript 对象表示法 (JSON) 对象的库,则对于使用 DLR 的语言,您的对象可以显示为动态对象。 这使库用户能够编写语法更简单且更自然的代码,以便操作对象和访问对象成员。 例如,在 C# 中,您可能会使用下面的代码来递增 XML 中的计数器值。 Scriptobj.SetProperty("Count", ((int)GetProperty("Count")) + 1); 通过使用 DLR,您可以改用下面的代码来执行相同的操作。 scriptobj.Count += 1; 与 CLR 类似,DLR 是 .NET Framework 的一部分,并随 .NET Framework 和 Visual Studio 安装包一起提供。 DLR 的开放源代码版本还可以从 CodePlex 网站下载获得。 C#4.0加入了dynamic关键字,可以申明一个变量的static类型为dynamic。
在3.0及之前,如果你不知道一个变量的类型,而要去调用它的一个方法,一般会用到反射:
object calc = GetCalculator();
Type calcType = calc.GetType();
object res = calcType.InvokeMember("Add",BindingFlags.InvokeMethod, null,new object[] { 10, 20 });int sum = Convert.ToInt32(res);
有了dynamic,就可以把上面代码简化为:
dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);
使用dynamic的好处在于,可以不去关心对象是来源于COM, IronPython, HTML DOM或者反射,只要知道有什么方法可以调用就可以了,剩下的工作可以留给runtime。
dynamic也可以用在变量的传递中,runtime会自动选择一个最匹配的overload方法。
这里有一个demo:把一段javascript代码拷到C#文件中,将var改成dynamic,function改成void,再改一下构造函数的调用方式(new type()改为win.New.type()),去掉javascript中的win.前缀(因为这已经是C#的方法了),就可以直接运行了。
dynamic的实现是基于IDynamicObject接口和DynamicObject抽象类。而动态方法、属性的调用都被转为了GetMember、Invoke等方法的调用。
泛型中的协变和逆变在C#中,下面的类型转换是非法的: IList<string> strings = new List<string>(); IList<object> objects = strings; 因为你有可能会这样做,而编译器的静态检查无法查出错误: objects[0] = 5; string s = strings[0]; 4.0中在声明generic的Interface及Delegate时可以加in及out关键字,如: public interface IEnumerable<out T> : IEnumerable{IEnumerator<T> GetEnumerator();}public interface IEnumerator<out T> : IEnumerator{bool MoveNext();T Current { get; }} public interface IComparer<in T>{public int Compare(T left, T right);} out关键字的意思是说IEnumerable<T>中T只会被用在输出中,值不会被改变。这样将IEnumerable<string>转为IEnumerable<object>类型就是安全的。 in的意思正好相反,是说IComparer<T>中的T只会被用在输入中,这样就可以将IComparer<object>安全的转为IComparer<string>类型。 前者被称为Co-Variance, 后者就是Contra-Variance。 .Net4.0中使用out/in声明的Interface: System.Collections.Generic.IEnumerable<out T>System.Collections.Generic.IEnumerator<out T>System.Linq.IQueryable<out T>System.Collections.Generic.IComparer<in T>System.Collections.Generic.IEqualityComparer<in T>System.IComparable<in T> Delegate: System.Func<in T, …, out R>System.Action<in T, …>System.Predicate<in T>System.Comparison<in T>System.EventHandler<in T> C# 5.0异步文件 I/O// Three things to note in the signature: // - The method has an async modifier. // - The return type is Task or Task<T>. (See "Return Types" section.) // Here, it is Task<int> because the return statement returns an integer. // - The method name ends in "Async." async Task<int> AccessTheWebAsync() { // You need to add a reference to System.Net.Http to declare client. HttpClient client = new HttpClient(); // GetStringAsync returns a Task<string>. That means that when you await the // task you'll get a string (urlContents). Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); // You can do work here that doesn't rely on the string from GetStringAsync. DoIndependentWork(); // The await operator suspends AccessTheWebAsync. // - AccessTheWebAsync can't continue until getStringTask is complete. // - Meanwhile, control returns to the caller of AccessTheWebAsync. // - Control resumes here when getStringTask is complete. // - The await operator then retrieves the string result from getStringTask. string urlContents = await getStringTask; // The return statement specifies an integer result. // Any methods that are awaiting AccessTheWebAsync retrieve the length value. return urlContents.Length; } 如果 AccessTheWebAsync 没有它可以完成调用 GetStringAsync 和等待计算完成之间的任何工作,通过调用和等待简化代码在下面的单个语句。
string urlContents = await client.GetStringAsync();
在异步方法,可以使用提供的关键字和类型指示要执行,因此,编译器执行方式,包括记录必须出现,当控件处于挂起的方法时回时间点。 某些实例处理,例如循环,而异常处理,可能很难进行在传统异步代码的句柄。 在异步方法,解决您编写这些元素,因为在一个同步解决方案会并将问题。 调用过程: 在关系图的数值对应于以下步骤。
如果您不熟悉异步编程,请需要一分钟考虑同步和异步行为之间的差异。 一个同步方法返回,其工作完成 (第 5 步),但是,异步方法返回任务值,其工作挂起时 (第 3 步和第 6 步)。 在异步方法最终完成其工作时,任务将会标记为已完成和结果,如果有,在任务中。 在什么情况下可能想知道找到支持异步编程的方法 (如 GetStringAsync。 .NET Framework 4.5 包含与异步以及等待的许多成员。 您可以通过附加到成员名称和 Task 或 Task<TResult>的返回类型“Async”后缀识别这些成员。 例如,System.IO.Stream 选件类包含方法例如 CopyToAsync、ReadAsync和 WriteAsync 在同步方法 CopyTo、Read和 Write。 异步方法旨在成为非阻塞操作。 当等待的任务运行时,在异步方法的一个等待表达式不会阻止当前线程。 相反,该表达式注册该方法的其余部分作为继续并返回控制对异步方法的调用方。 异步和等待关键字不会导致其他线程创建。 因为异步方法本身并不会运行的线程,异步方法不需要多线程。 只有 + 当方法处于活动状态,则方法在当前同步上下文中运行并使用在线程的时间。 可以使用 Task.Run 移动 CPU 工作移到后台线程,但是,后台线程不利于等待结果变得可用处理。 以异步编程的基于异步的方法优于于几乎每个用例的现有方法。 具体而言,此方法比 IO 操作的 BackgroundWorker 好,因为代码更为简单的,因此无需防止争用条件。 与 Task.Run的组合,异步编程的 CPU 操作的 BackgroundWorker 好,因为异步编程从 Task.Run 传输到线程池的工作分隔运行您的代码以协调详细信息。 如果指定使用 异步 或 异步 修饰符,方法是异步方法,可以实现以下两个函数。
异步方法通常包含等待运算符的一个或多个匹配项,但是,请假等待表达式不会导致编译器错误。 如果异步方法不会将等待运算符指示悬挂点,方法尽管"修饰符执行,一个同步方法。 编译器会发出此类方法的警告。 Async 、async、Await和 await 是上下文关键字。 有关更多信息和示例,请参见以下主题: 在编程 .NET framework,异步方法通常返回 Task 或 Task<TResult>。 在异步方法中,等待运算符应用于从调用返回到另一个异步方法的任务。 您指定 Task<TResult>,因为返回类型,则方法包含指定类型 TResult操作上的一个 返回 (Visual Basic) 或 返回 (c#) 语句。 使用 Task,因为返回类型,则该方法没有返回语句或具有不返回操作线程的 return 语句。 下面的示例演示如何声明并调用返回 Task<TResult> 或 Task的方法。 // Signature specifies Task<TResult> async Task<int> TaskOfTResult_MethodAsync() { int hours; // . . . // Return statement specifies an integer result. return hours; } // Calls to TaskOfTResult_MethodAsync Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync(); int intResult = await returnedTaskTResult; // or, in a single statement int intResult = await TaskOfTResult_MethodAsync(); // Signature specifies Task async Task Task_MethodAsync() { // . . . // The method has no return statement. } // Calls to Task_MethodAsync Task returnedTask = Task_MethodAsync(); await returnedTask; // or, in a single statement await Task_MethodAsync(); 每个返回的任务表示正在进行的工作。 任务封装有关状态的信息异步过程和,最后,从进程的最终结果或处理引发的异常;如果未成功。 异步方法也是 Sub 方法 (Visual Basic) 或使 void 返回类型 (c# 中)。 这将返回类型主要用于定义事件处理程序,void 返回类型需要。 异步事件处理程序通常用作异步程序的起始点。 是 Sub 程序或具有 void 返回类型不能等待的异步方法和一个无效返回的方法的调用方无法捕获方法引发的任何异常。 异步方法不能声明在 Visual Basic 或 ref 的 ByRef 参数或在 C# 中 http://msdn.microsoft.com/zh-cn/library/t3c3bfhx.aspx 参数,但是,方法可以调用具有这些参数的方法。 有关更多信息和示例,请参见异步返回类型(C# 和 Visual Basic)。 有关如何捕获异步方法的异常的更多信息,请参见 try-catch(C# 参考) 或Try...Catch...Finally 语句 (Visual Basic)。 在 Windows 运行时 编程的异步 API 使之一返回类型,类似于任务:
有关更多信息和示例,请参见 快速入门:使用异步编程的时间运算符。 按照约定,您追加“Async”传递给具有 Async 或 async 修饰符方法的名称。 您可以忽略事件、基类或接口协定建议一个不同的名称约定。 例如,您不应向常用事件处理程序重命名,例如 Button1_Click。
弱事件 |
请发表评论