c#4.5新特性
2019-06-27 08:57:01 qq_26800875 阅读数 26

 

 

 

方法异步执行15秒、同步执行会30秒,所以此方法简单有效

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace CloudLearning.UI
{
    class Program
    {
        static void Main(string[] args)
        {
            AsyncPrintHelloWorld();
            Console.ReadLine();
        }
 
        public async static void AsyncPrintHelloWorld()
        {
            Console.WriteLine("异步方法调用开始");  
            var result1 = TMothd1();
            var result2 = TMothd2();
            var result3 = TMothd3();
            Console.WriteLine("异步方法完成");
            int r1 = await result1;
            int r2= await result2;
            int r3 = await result3;
            Console.WriteLine("{0},{1},{2}", r1, r2, r3);
        }
 
        public async static Task<int> TMothd1()
        {
            return await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(5 * 1000);
                Console.WriteLine("TMothd1 完成");
                return 1;
            });
        }
 
        public async static Task<int> TMothd2()
        {
            return await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(10 * 1000);
                Console.WriteLine("TMothd2 完成");
                return 2;
            });
        }
        public async static Task<int> TMothd3()
        {
            return await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(15 * 1000);
                Console.WriteLine("TMothd3 完成");
                return 3;
            });
        }
 
    }
}
 

2018-04-01 14:17:00 qq_27211375 阅读数 2

 

  1.字符串中调用参数

DataTable dt= sqlHelper.SqlConnectionInformation(connstr,sql);
string rows = JsonConvert.SerializeObject(dt);

string json = $"{{\"total\":{dt.Rows.Count},\"rows\":{rows}}}";

  需要注意{{}}是转义的{}

2007-01-25 17:08:00 luqinghua 阅读数 493

这篇文章只是学习 迭代器 和匿名方法 的一些实例代码,并没有什么技术含量:

    #region 迭代器

    public class SampleCollection
    {
        public object[] array;

        public SampleCollection(object[] oArray)
        {
            array = oArray;
        }

        public System.Collections.IEnumerable BuildCollection()
        {
            for (int i = 0; i < array.Length; i++)
            {
                yield return array[i];
            }
        }
    }

    public class UseCollection
    {
        public void GetSingleItem()
        {
            object[] oarray = new object[] { "a","b"};
            SampleCollection cole = new SampleCollection(oarray);
            string strColl = "";
            foreach (object osin in cole.BuildCollection())
            {
                strColl += osin.ToString();
            }
        }
    }

    #endregion

    #region 匿名方法

    public class SubClass
    {
        delegate void SomeDelete();

        public void InvokMethod()
        {
            SomeDelete de = delegate()
            {
                //方法体
                string str = "1";
                string str1 = str;
            };
           
            de();
        }

        //常规调用
        void Method()
        {
            //方法体
            string str = "1";
            string str1 = str;
        }
        public void InvokeMe()
        {
            SomeDelete sun = new SomeDelete(Method);
            sun();
        }
    }
    #endregion

2009-05-21 16:13:00 kcseason 阅读数 765
 

C# 2.0新特性与C# 3.5新特性

一、C# 2.0 新特性:

1、泛型
List<MyObject> obj_list=new List();
obj_list.Add(new MyObject());

2、部分类(partial)
namespace xxx
{
public partial class Class1
{
private string _s1;
public string S1
{
get { return _s1; }
set { _s1 = value; }
}
}

//或在另一个文件中
public partial class Class1
{
public string GetString()
{
string s = this.S1 + "aaa";
return s;
}
}
}


3、静态类
public static class MyStaticObject
{
private static string _s;
static MyStaticObject()
{
_s = "Hello";
}
public static string Mothed1()
{
return _s + ",world.";
}
}

4、属性访问器可访问性
public class Class2
{
private string _str;
public string Str
{
get { return _str; }
protected set { _str = value; }
}
}

5、可空类型
int? aa = null;
aa = 23;
if (aa.HasValue)
{
int bb = aa.Value;
}


6、匿名方法
class SomeClass //在C#1.0中
{
delegate void SomeDelegate();
public void InvokeMethod()
{
SomeDelegate del = new SomeDelegate(SomeMethod);
del();
}
void SomeMethod()
{
MessageBox.Show("Hello");
}
}

class SomeClass2
{
public delegate void SomeDelegate();
public void InvokeMothed()
{
SomeDelegate del = delegate {
MessageBox.Show("Hello");
};
del();
}
}


7、名称空间别名限定符
global::

 

二、C# 3.0/3.5 新特性:
1、LinQ(语言集成查询)
以前,查询XML文件使用XPath,数据库刚用SQL,LinQ搜索任何IEnumerable数据源.
在ORM解决方案中,LINQ对象用途很大.
示例:
List customers = new List();
IEnumerable query_result = from c in customers
where c.Money > 100
orderby c.Name
select c;
Linq 包括 Linq to SQL, Linq to Objects, Linq to XML 和 ADO.NET Entity Framework 等几个部分

2、Lambda表达式。更激动人心的,是一种匿名函数结构,它可以方便的实现委托、查询综合和扩展方法的 delegate 类型参数的初始化定义.
示例:原来的:
delegate void Func(int x);
void Add(int x){x++;}
Func f=new Func(Add);
f(1);
可简化为:
Func f=(x)=>{x++;};
或:
Func f=(int x )=>{x++;};


3、隐式类型本地变量。var关键字(类型脚本语言中的隐式声明变量,主要针对LinQ设计)
var num=0;
var nums[]={1,2,3,4,5};
var num='a';
var list=new List();
foreach(var i in nums){
num+=i;
}

4、扩展方法。extension(允许您扩充任何类,甚至是标记为封装的类,对于扩展的方法必须在静态类里来扩展)
示例,在string上实现Count()方法:
using System.Runtime.CompilerService;
public class Extensions{
[Extension()]
public int Count(this string source){
int count = 0;
foreach (var item in source){
count++;
}
return count;
}
}
//使用:
string s="Hello,world!";
int i=s.Count();


5、对象和集合初始值设定项。初始化的简化,写实体类方便了
public class Person{
public string Name{get;set;} //自动实现属性
public int Age{get;set;}
}
var person1=new Person{Name="tang",Age=21}; //...
var persons=new List{ //集合初始化器
new Person{Name="TEW",Age=21},
new Person{Name="RSA",Age=18}
};

6、宽松委托。宽松委托使得 C# 在判断委托实例化赋值时,对于签名不同的函数可以接受。例如 EventArgs 和 MouseEventArgs 是具备继承关系的类,当它们出现在同一个接受 EventArgs 类型参数的委托定义中时,编译器对于这两种委托都能接受。例如:

delegate void A (object sender, MouseEventArgs e);
delegate void B (int a, int b);

EventHandler e1, e2;
e1 = new A(...);    // OK
e2 = new EventHandler(...);   // OK
e1 = e2;    // OK

B b = (long a, int b) +> ...{ };   // OK

7、自动实现属性。

在定义类的属性时,常常需要像下面的代码一样封装一个域。

private string name;

public string Name ...{ get ...{ return name; } set ...{ name = value; } }
C# 3.0 提供了一种简化的属性定义方法,可以实现上述代码的作用。

public string Name ...{ get; set; }
这就是自动实现属性。编译器自动实现类似域封装的代码。不过自动实现属性不能定义只读和只有 get 过程的属性;set 也不能具备访问性描述。

8、匿名类型

匿名类型常常用在查询表达式的结果中,因为这种类型的返回值往往是一个包含一种特定类型的 IEnumerable<T>。例如,要从上面的例子中选出年龄大于 21 岁,身高大于 160 厘米的 Person 集合,可以采用如下形式。

 

var result = from person in persons where person.Age >= 21 && person.Height >= 160
    select new ...{ Name = person.Name, Age = person.Age, Height = person.Height / 100 };

new { Name = person.Name, Age = person.Age, Height = person.Height / 100 } 是一个匿名类型,编译器将对它做如下声明。

 

public class _Anonymous_Name_Age_Height ...{
    public string Name;
    public string Age;
    public decimal Height;
}

9、分部方法(partial分部类的分部方法,必须是void返回类型)
// 文件 1.cs
public partial class A{
void B(); //声明
}

// 文件 2.cs
public partial class A{
void B { Console.WriteLine("B invoked."); } //实现
}

这种语法可以把函数的定义和声明分开编写。使用分部方法需要注意:

1、分部方法的类实体必须为 partial。
2、分部方法的返回值必须为 void。
3、如果没有实现分部方法,但却定义了此方法的声明,在使用这个包含分部方法的类时,编译器自动将没有实现的方法签名移除。

2017-09-08 18:25:36 hetoby 阅读数 608

C#7.1

C#7

1.out variables

//以前必须先定义,再使用,不在同一行上,而且有可能没有赋值就使用
int numericResult;
if (int.TryParse(input, out numericResult))
    WriteLine(numericResult);
else
    WriteLine("Could not parse input");

//现在可以在使用的地方定义,变量作用域会自动“leaks"到外面
if (int.TryParse(input, out int result))
    WriteLine(result);
else
    WriteLine("Could not parse input");
//而且可以使用var类型推断
if (int.TryParse(input, out var answer))
    WriteLine(answer);
else
    WriteLine("Could not parse input");

2.System.ValueTuple

//1).要使用,需要通过NuGet下载System.ValueTuple包
//2).声明和访问元素
//未指定每个field的名字,自动用Item1, Item2...
var letters = ("a", "b");

//左侧指定每个field的名字
(string Alpha, string Beta) namedLetters = ("a", "b");

//右侧指定每个field的名字
var alphabetStart = (Alpha: "a", Beta: "b");

//两边都指定以左边为尊,同时获得一个警告
(string First, string Second) firstLetters = (Alpha: "a", Beta: "b");

System.Diagnostics.Trace.WriteLine($"{namedLetters.Alpha},{letters.Item1}, 
{alphabetStart.Beta}, {firstLetters.First}");

//3).tuple最常用的地方:作为函数返回值,省去定义结构
List<int> numbers = new List<int>() { 10, 1, 9, 7, 20, 8 };
//返回的是tuple,其成员是Min,Max
var range = Range(numbers);
System.Diagnostics.Trace.WriteLine($"range is [{range.Min}, {range.Max}]");

//4).解构tuple
//有时可能需要解构元组(deconstructing tuple),这可以通过为元组中的每个值声明独立的变量来实现
(int max, int min) = Range(numbers);
System.Diagnostics.Trace.WriteLine($"range is [{min}, {max}]");

//5).可以为任何.net类型提供deconstruction功能
//要实现这个功能,需要为类添加一个名为Deconstruct的成员函数,
//并为你像想要抽取的成员提供参数类型为out的参数
var p = new MyPoint(1, 2, 3);
(double X, double Y, double Z) = p;//解构MyPoint
//名字可以和Deconstruct里面的不一样,它们并非邦死的
(double horizontalDistance, double verticalDistance, double z) = p;

//for 3). and 4).
//tuple最有用的地方是作为private/internal方法的返回值, 这省去了创建class/struct类型作为返回值
private static (int Max, int Min) Range(IEnumerable<int> numbers)
{//好处如下:
//You save the work of authoring a class or a struct that defines the type returned.
//You do not need to create new type.
//The language enhancements removes the need to call the Create<T1>(T1) methods.
    int min = int.MaxValue;
    int max = int.MinValue;
    foreach (var n in numbers)
    {
        min = (n < min) ? n : min;
        max = (n > max) ? n : max;
    }
    return (max, min);
}

//for 5).
public class MyPoint
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }

    public MyPoint(double x, double y, double z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }

    //要实现Deconstruction功能,需要为类添加一个名为Deconstruct的成员函数,
    //并为你像想要抽取的成员提供参数类型为out的参数
    public void Deconstruct(out double x, out double y, out double z)
    {
        x = this.X;
        y = this.Y;
        z = this.Z;
    }
}

C#6

1.Read-only auto-properties 只读自动属性
以前版本:类内部可以set这两个属性

public string FirstName { get; private set; }
public string LastName { get; private set; }

新版本:只有在构造函数里面可以设置这两个属性

public string FirstName { get; }
public string LastName { get;  }

2.Auto-Property Initializers 自动属性初始化器
允许在声明自动属性(无论是只读还是读写)的同时给它赋初值

public ICollection<double> Grades { get; } = new List<double>();
public Standing YearInSchool { get; set;} = Standing.Freshman;

3.Expression-bodied function members表达式函数成员
支持method 和 read-only property.

public class Student
{   //auto-property
    public string FirstName { get; set; } = "FirstName";
    public string LastName { get; set; } = "LastName";

    //public field
    public int ID;

    //It works for methods and read-only properties.
    //只读属性(别和上面的ID域混淆)举例
    public string FullName => $"{FirstName}.{LastName}";
    //函数举例
    public override string ToString() => $"{FullName}";
}
var s = new Student();
System.Diagnostics.Trace.WriteLine(s.ToString());
s.FullName = "abc";//error, readonly
s.ID = 7;//ok

4.using static
using static导入的静态方法;using则导入namespace里的所有。
最好的一个例子是System.Math,因为它里面没有实例方法。

以前不能using System.Math,因为System.Math不是namespace;
现在可以using static System.Math,因为using static可以导入类的静态方法。
注意即使一个类不全是静态方法,也可以用这种方法导入它的静态方法,比如System.String。

//注意Math和String都是类
using static System.Math;
Sqrt(2);

using static System.String;//注意要使用String而不是string
if (IsNullOrWhiteSpace(lastName))
{
}

using static不包括extension methods,因为扩展方法实际使用的是类实例对象。

5.Null-conditional operators(null条件操作符)
访问对象之前通常都需要判空以免引用空对象。null条件操作符”?.”提供了方便。

//person为null,则返回null;否则返回person.FirstName
//表达式的返回类型为null或者string
var first = person?.FirstName;
//经常和null coalescing operator(??)一起使用
//表达式的返回类型为string
var first = person?.FirstName ?? "Unspecified";

“?.”运算符保证操作符前面的值只被求值一次,这比用if语句判空更准确

//if判断的时候可能不为空,但使用的时候可能已经为空了
var handler = this.SomethingHappened;
if (handler != null)
    handler(this, eventArgs);
if (this.SomethingHappened != null)
    this.SomethingHappened(this, eventArgs);
//如果使用"?."可以保证此操作符前面的值只被求值一次,避免上述情况
this.SomethingHappened?.Invoke(this, eventArgs);

6.String Interpolation(字符串插值)
C#6提供了比string.format更简洁的语法”$”

public string FullName
{
    get
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }
}
简化为:
public string FullName => $"{FirstName} {LastName}";

格式化输出,”$”支持string支持的所有format控制,用”:”指定格式控制符

public string GetFormattedGradePoint() =>
    $"Name: {LastName}, {FirstName}. G.P.A: {Grades.Average()}";

//控制2位浮点数
public string GetGradePointPercentage() =>

//使用"?:"表达式时,要注意用括号来区别格式控制符
public string GetGradePointPercentages() =>
    $"Name: {LastName}, {FirstName}. G.P.A: {(Grades.Any() ? Grades.Average() : double.NaN):F2}";

//"$"里面的表达式没有任何显示,你可以使用想用的任何表达式,包括复杂的LINQ查询
public string GetAllGrades() =>
    $@"All Grades: {Grades.OrderByDescending(g => g)
    .Select(s => s.ToString("F2")).Aggregate((partial, element) => $"{partial}, {element}")}";

//"$"还支持指定specific cultures
FormattableString str = @"Average grade is {s.Grades.Average()}";
var gradeStr = string.Format(null, 
    System.Globalization.CultureInfo.CreateSpecificCulture("de-de"),
    str.GetFormat(), str.GetArguments());

7.Exception Filters(异常过滤)
当过滤表达式为true时,执行catch;否则,跳过catch.

用法之一是用于检查catch从句是否能处理某种异常(One use is to examine information about an exception to determine if a catch clause can process the exception)

//以前这样写
public static async Task<string> MakeRequest()
{ 
    var client = new System.Net.Http.HttpClient();
    var streamTask = client.GetStringAsync("https://localHost:10000");
    try {
        var responseText = await streamTask;
        return responseText;
    } catch (System.Net.Http.HttpRequestException e)
    {
        if (e.Message.Contains("301"))
            return "Site Moved";
        else
            throw;//这样做,将导致原始异常抛出点到这里的信息丢失,而使用异常过滤可以避免这种情况发生。
        //The actual exception object will contain the original call stack,
        //but all other information about any variables in the call stack 
        //between this throw point and the location of the original throw point has been lost.
    }
}
//现在可以这样写
public static async Task<string> MakeRequest()
{ 
    var client = new System.Net.Http.HttpClient();
    var streamTask = client.GetStringAsync("https://localHost:10000");
    try {
        var responseText = await streamTask;
        return responseText;
    } catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
    {
        return "Site Moved";
    }
}

用法之二是用于log例程,让log例程始终返回false,利用when过滤来记录log。
Another recommended pattern with exception filters is to use them for logging routines. This usage also leverages the manner in which the exception throw point is preserved when an exception filter evaluates to false.

//log例程是参数为Exception,返回值始终为false的函数,如下:
//A logging method would be a method whose argument is the 
//exception that unconditionally returns false
public static bool LogException(this Exception e)
{
    Console.Error.WriteLine(@"Exceptions happen: {e}");
    return false;
} 
//当需要记录异常时,可以如下使用:
//Whenever you want to log an exception, you can add a catch clause, 
//and use this method as the exception filter:
public void MethodThatFailsSometimes()
{
    try {
        PerformFailingOperation();
    } catch (Exception e) when (e.LogException())
    {//因为e.LogException始终返回false(只有return true才会进来),所以这里永远执行不到。
     //这就使得我们可以通过这种方法,在任何异常处理之前,记录异常。
        // This is never reached!
        //The exceptions are never caught, because the LogException method always returns false. 
    }
} 
//先记录异常,然后处理异常
public void MethodThatFailsButHasRecoveryPath()
{
    try {
        PerformFailingOperation();
    } catch (Exception e) when (e.LogException())
    {//e.LogException记录异常,并返回false,所以这里永远执行不到
        // This is never reached!
    }
    catch (RecoverableException ex)
    {//记录完之后,然后开始处理异常
        Console.WriteLine(ex.ToString());
        // This can still catch the more specific
        // exception because the exception filter
        // above always returns false.
        // Perform recovery here 
    }
}

用法之三是Another recommended pattern helps prevent catch clauses from processing exceptions when a debugger is attached. This technique enables you to run an application with the debugger, and stop execution when an exception is thrown.

public void MethodThatFailsWhenDebuggerIsNotAttached()
{
    try {
        PerformFailingOperation();
    } catch (Exception e) when (e.LogException())
    {
        // This is never reached!
    }
    catch (RecoverableException ex) when (!System.Diagnostics.Debugger.IsAttached)
    {
        Console.WriteLine(ex.ToString());
        // Only catch exceptions when a debugger is not attached.
        // Otherwise, this should stop in the debugger. 
    }
}
After adding this in code, you set your debugger to break on all unhandled exceptions. Run the program under the debugger, and the debugger breaks whenever PerformFailingOperation() throws a RecoverableException. The debugger breaks your program, because the catch clause won't be executed due to the false-returning exception filter.

8.nameof表达式
用于获取symbol的名字,这是用于获得变量,属性,成员字段名称的好方法。
使用这种方法而不是直接使用常量的好处是:重构时不需要一个一个去修改。

//One of the most common uses for nameof is to provide the name 
//of a symbol that caused an exception:
if (IsNullOrWhiteSpace(lastName))
    throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));

//Another use is with XAML based applications that 
//implement the INotifyPropertyChanged interface:
private string lastName;
public string LastName
{
    get { return lastName; }
    set
    {
        if (value != lastName)
        {
            lastName = value;
            PropertyChanged?.Invoke(this, 
                new PropertyChangedEventArgs(nameof(LastName)));
        }
    }
}

//nameof获得的是不完全限定名,即使nameof(这里用完全限定名),结果也是非完全限定名。
private string firstName;
public string FirstName
{
    get { return firstName; }
    set
    {
        if (value != firstName)
        {
            firstName = value;
            PropertyChanged?.Invoke(this, 
                new PropertyChangedEventArgs(nameof(UXComponents.ViewModel.FirstName)));
        }
    }
}
//这里nameof(UXComponents.ViewModel.FirstName)的结果是FirstName,
//而不是UXComponents.ViewModel.FirstName

9.Await in Catch and Finally blocks(catch/finally中可以使用await)
之前的版本await可以使用的地方是有限制的,比如在catch/finally语句块里面就不能使用;C#6则支持。
在catch/finally block中添加await表达式,会使处理过程变得复杂。在任何异步方法中都可以在catch/finally中使用await,下面是一个例子。

//With C# 6, you can also await in catch expressions. 
//This is most often used with logging scenarios:
public static async Task<string> MakeRequestAndLogFailures()
{ 
    await logMethodEntrance();
    var client = new System.Net.Http.HttpClient();
    var streamTask = client.GetStringAsync("https://localHost:10000");
    try {
        var responseText = await streamTask;
        return responseText;
    } 
    //下面在catch/finally中使用await确保行为和同步执行的代码是一样的
    //ensure that the behavior is consistent with the behavior for synchronous code. 
    //catch/finally里面的代码抛出异常,会在下面的查找合适的catch//如果抛出的异常就是当前这样的异常,那这个异常将丢失。
    //同样的,如果await表达式抛出异常,也会查找合适的catch,并且当前的异常(如果有的话)也会丢失。
    //When code executed in a catch or finally clause throws, 
    //execution looks for a suitable catch clause in the next surrounding block. 
    //If there was a current exception, that exception is lost. 
    //The same happens with awaited expressions in catch and finally clauses: 
    //a suitable catch is searched for, and the current exception, if any, is lost.
    catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
    {
        await logError("Recovered from redirect", e);
        return "Site Moved";
    }
    finally
    {
        await logMethodExit();
        client.Dispose();
    }
    //以上例子也说明了:我们在写catch/finally时要特别小心,要避免引起新的异常。
}

10.Index Initializers(索引初始化器)
以前只能顺序初始化

//现在
private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
    [404] = "Page not Found",
    [302] = "Page moved, but left a forwarding address.",
    [500] = "The web server can't come out to play today."
};

11.Extension methods for collection initializers(集合初始化的扩展方法)
之前的版本,是无法像下面的代码这样使用Enrollment object来初始化集合的,尽管Enrollment类提供了Enroll方法来添加student。
You could not use collection initializers with an Enrollment object(The Enroll method adds a student. But it doesn’t follow the Add pattern).

public class Enrollment : IEnumerable<Student>
{
    private List<Student> allStudents = new List<Student>();
    public void Enroll(Student s)
    {
        allStudents.Add(s);
    }
    public IEnumerator<Student> GetEnumerator()
    {
        return ((IEnumerable<Student>)allStudents).GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<Student>)allStudents).GetEnumerator();
    }
}
//之前是无法这样初始化自定义的集合的
var classList = new Enrollment()
{
    new Student("Lessie", "Crosby"),
    new Student("Vicki", "Petty"),
    new Student("Ofelia", "Hobbs")
};

新版里面我们可以通过扩展方法来实现。具体做法是:创建一个名为Add的扩展方法,并把一个添加元素的方法映射到这个Add方法。本例为:创建一个Add扩展方法并映射到Enroll方法(因为Enrollment类是通过Enroll方法添加元素的)。

//创建扩展方法
public static class StudentExtensions
{
    public static void Add(this Enrollment e, Student s) => e.Enroll(s);
}
public class Enrollment : IEnumerable<Student>
{
    private List<Student> allStudents = new List<Student>();
    public void Enroll(Student s)
    {
        allStudents.Add(s);
    }
    public IEnumerator<Student> GetEnumerator()
    {
        return ((IEnumerable<Student>)allStudents).GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<Student>)allStudents).GetEnumerator();
    }
}
//然后我们就可以这样初始化集合对象了
var classList = new Enrollment()
{
    new Student("Lessie", "Crosby"),
    new Student("Vicki", "Petty"),
    new Student("Ofelia", "Hobbs")
};

12.Improved overload resolution(提高重载解析度)

static Task DoThings() 
{
     return Task.FromResult(0); 
}
//以前的版本只能这样用:
System.Threading.Tasks.Task.Run(() => DoThings());
//因为以前的编译器无法正确的区分Task.Run(Action)Task.Run(Func<Task>()),
//所以需要用lambda表达式作为参数。

//现在则可以区分,所以可以这样用:
System.Threading.Tasks.Task.Run(DoThings);

C#新特性

阅读数 11

C#新特性

阅读数 12

没有更多推荐了,返回首页