C# 6 已经在随VS2015 RC正式发布。。有兴趣的童鞋可以观看在Build 2015中的介绍视频。。
What's New in C# 6 and Visual Basic 14

里面有很多本文中没有提到的特性哟。。

BTW:C# 7的功能清单已经在出了。。
C# 7 Work List of Features · Issue #2136 · dotnet/roslyn · GitHub


--------我是华丽的分割线--------

稍微列举一下 C# 6 中将要出现的奇技淫巧吧~
参考自 New Features in C# 6 ,有删改~

作为一门专为程(yu)序(fa)员(tang)考虑的语言,感受一下来自微软的满满的恶意...

1. 字符串内联
在之前的版本中,常用的格式化字符串:

var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);
在 C# 6 中:
//无格式
var s = $"{p.Name} is {p.Age} year{{s}} old";

//带格式
var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";

//带子表达式
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";

2. 空条件运算符
在之前的版本中对于 可空类型 动态类型 ,获取子元素往往较为复杂:
if(someSchool != null && someSchool.someGrade != null && someSchool.someGrade.someClass != null)
{
    return someSchool.someGrade.someClass.someOne;
}
在 C# 6 中,引入了新的运算符:
return someSchool?.someGrade?.someClass?.someOne;
//也可以使用下标运算,例如
//return someArray?[0];
如果 ?. 运算符的左项为 null ,则直接返回 null 。
对于方法或者委托的执行,可以使用 Invoke:
someMethod?.Invoke(args);

3. nameof 表达式
可以直接返回传入变量的名称,而无需复杂的反射。
int someInt;
Console.WriteLine(nameof(someInt)); //"someInt"
注:如果是前面带有命名空间和/或类名,只返回最后的变量名。

4. 索引初始化器
在 C# 6 中简化了对 Dictionary 的初始化方法:
var numbers = new Dictionary<int, string> { 
    [7] = "seven", 
    [9] = "nine", 
    [13] = "thirteen" 
};

5. 条件异常处理
在 C# 6 中可以选择性地对某些异常进行处理,无需额外增加判断过程:
try {  } 
catch (MyException e) if (myfilter(e)) 
{ 
     
}

6. 属性初始化器
在 C# 6 中可以直接对属性进行初始化:
public class Customer 
{ 
    public string First { get; set; } = "Jane"; 
    public string Last { get; set; } = "Doe"; 
}
以及可以类似定义只读的属性。

7. 成员函数的 lambda 定义
在 C# 6 中可以使用 lambda 表达式来定义成员方法。
public class Point
{
    public Point Move(int dx, int dy) => new Point(x + dx, y + dy); 
    public static Complex operator +(Complex a, Complex b) => a.Add(b); 
    public static implicit operator string(Person p) => $"{p.First}, {p.Last}";
}

8. 结构体的无参构造函数
在 C# 6 中可以创建结构体的不带参数的构造函数。
struct Person 
{ 
    public string Name { get; } 
    public int Age { get; } 
    public Person(string name, int age) { Name = name; Age = age; } 
    public Person() : this("Jane Doe", 37) { } 
}

9. using 静态类
在 C# 6 中 using 除了可以用于命名空间也可以用于静态类。
using System.Console; 
using System.Math;

class Program 
{ 
    static void Main() 
    { 
        WriteLine(Sqrt(3*3 + 4*4)); 
    } 
}

大体感觉主要就是这些内容... (o=>_<=o)

1、泛型类型字典,这个已经基本不算奇技淫巧了,因为大家都在用:

    private static class ConverterCache<T>
    {
      public static IDbValueConverter<T> ConverterInstance { get; set; }
    }
上面是随便从我一个项目里面摘出来的最简单的类型字典的例子,一个最简单的类型字典只需要一个泛型类,和一个静态字段就够了。

详细请参考:
泛型技巧系列:类型字典和Type Traits


2、利用using来做Scope,其实我个人不是很喜欢这个技巧,在ASP.NET MVC里面广泛使用:
using( Html.BeginForm() )
{
  //...
}

3、其实扩展方法可以做很多好玩的东西:
public static T CastTo<T>( this object obj )
{
  return (T) obj;
}

public static T IfNull<T>( this T value, T defaultValue )
{
  if ( value == null || Convert.IsDBNull( value ) )
    return defaultValue;
  else
    return value;
}

我还有一个扩展方法把一个类型所有属性和属性值转换成一个Dictionary的,代码就不贴了,除了一些常规用途,有时候初始化一个Dictionary很麻烦的时候,还可以直接new一个匿名对象,再用这个扩展方法转成Dictionary就完了。

4、运算符重载
运算符重载理论上不算什么奇技淫巧,是个标准特性,但不知道为什么用的人特别少。

var logger = new ConsoleLogger() + new TextFileLogger( @"C:\Temp\Logs\1.log" );
我的LogUtility,可以将多个Logger用+连接起来,一并记录日志。


5、dynamic绑定
dynamic说白了就是运行时绑定,而且绑定到什么逻辑上是可以在运行时再根据上下文重新定义的。劣势是没有智能提示,但有些地方根本不需要智能提示,或者没有强类型,例如数据绑定。

我们现在的页面数据绑定已经开始倾向于大量使用dynamic,这样一来页面数据绑定便可以先行,根本用不着更新组件接口神马的,需要什么东西直接绑,反正不到运行时不会检测这个东西是不是存在。
而运行时真正执行这个绑定的时候,因为是代码逻辑,所以可以玩出很多花样。

最简单的花样像是大小写不敏感,绑定name属性,找到了一个叫做Name的属性,把值给他就好了。

复杂一点的花样,例如找不到Name属性,就输出一个字符串"[Name]"然后页面上就看到:
姓名:[Name]
这样一来,前端页面原型完全可以演示,根本不用等后面的数据对接,啥时候对接完了,自然变成最终的数据。

再复杂一点的,譬如有个属性改名了,原来的名字不存在了,没事,映射到新的名字,维护一个改名兼容表就完了。


其他的想到再补充。

SIMD支持
居然没有提到最新的SIMD指令支持啊,这个貌似碉堡:

// 两个整数数组相加的常规方法
for (int i = 0; i < size; i++) 
{ 
    C[i] = A[i] + B[i]; 
} 
// SIMD 方法, 每次几个元素同时相加,Vector<int>.Count是每个SSE/AVX寄存器容纳int的个数
using System.Numerics.Vectors;
for (int i = 0; i < size; i += Vector<int>.Count) 
{ 
    Vector<int> v = new Vector<int>(A,i) + new Vector<int>(B,i); 
    v.CopyTo(C,i); 
} 
更碉堡的是,Vector方法是硬件自适应的。也就是说,如果你的硬件只支持SSE2,就每四个int相加,如果支持AVX2,就每8个相加。

无GC模式
调用GC.TryStartNoGCRegion(int64)函数,传入一个内存大小(比如1G)。CLR会开辟一个指定大小的内存区域,然后进入无GC模式。适用于critical path部分的业务逻辑。

我觉得 泛基是一种很棒的技巧 这个名字是和 @赵劼 一同起的。

public abstract class MyBase<T> where T :MyBase <T> //被人肉编译器 @vczh 发现少写了<T>

{

	public static string DataForThisType {get;set;}
	public static T Instance{get;protected set;}
	//老赵说的邪恶的部分:让父类操作子类出现了
	public static readonly IReadOnlyDictionary<string,MemberInfo> Members
		=typeof(T)
			.GetMembers()
			.ToDictionary(x=>x.Name);

}



public class MyClass:MyBase<MyClass>
{

	static MyClass()
	{ 
		DataForThisType =string.Format(
			"MyClass got {0} members",Members.Count);
		Instance = new MyClass();
	}

}

子类的static 成员互相不干涉


@赵劼
简单说就是让父类可以静态化地知道当前子类…

------------

补充用途:

1 你有时候希望在父类规定一些行为,让子类无法修改,但是这些实现是依赖一个子类才能获取的值,你又不可能知道所有的子类 ,没办法替它在父类里面初始化,这时候就需要在父类里面定义一个每个子类一个的,但又是静态的空间。

2 你需要每个子类都有一些公开的静态成员,这些成员的类型是子类类型

3 在不知道子类具体类型的情况下,让父类利用泛型参数先替未来的子类做一些事情。


-----

貌似能实现这样功能的其他语言不多。 可是我没有挨个试验过 有人能有反馈告诉我自己熟悉的语言能否做到的话,感激不尽。

基本上看SO的这个问题就够了:
tips and tricks
给__arglist等关键字添个示例吧:

class Program
{
    [DllImport("msvcrt.dll")]
    public static extern int printf(string format, __arglist);
    
    [DllImport("msvcrt.dll")]
    public static extern int scanf(string format, __arglist);
    
    public static void WriteTypes(__arglist)
    {
        ArgIterator ai = new ArgIterator(__arglist);
        while(ai.GetRemainingCount() >0)
        {
            TypedReference tr = ai.GetNextArg();
            Console.WriteLine("Type:{0}", __reftype(tr));
            Console.WriteLine("Value:{0}", __refvalue(tr, int));
        }
    }
    
    static void Main(string[] args)
    {
        int x, y;
        scanf("%d%d", __arglist(out x, out y));
        printf("hello %d\nhello %x\n", __arglist(x, y));
        WriteTypes(__arglist(x, y));
    }
}

能写一行代码绝不写两行!

以下两个变量都可能为NULL

     object a = null;
     string b = null;
按照我以前的写法就需要这样.....
    if (a == null ) //或者是 b
    {
       a1 = "";
    }
    else
    {
       a1 = a.ToString();
    }
后来改成三元运算符...
a1 = a == null ? "" : a.ToString();

再后来看书学了一招...
  object a1 = a ?? "";
  string b1 = b ?? "";
//或者
  string a1 =(a ?? "").ToString()

再后来无意间反编译自己以前写的程序发现了目前最爱的用法:
string a1 = a + "";
管你是什么类型,返回都是字符串,NULL 也不会报错的。
因为....

如果不计较性能,这也许是我最值得炫耀的简化成果了。

------------------------2015-01-10----------------------------------
string a1 = a + "";
上面的情况是当a类型为 string 的情况。
当a是 object 时会被编译成 string a1 = string.Concat(a);
至于string.Concat方法...
编译器就是赞~

补一个博客!
不计代价的简化代码

伪多继承似乎没人说到:
比方说扫帚已经是清洁工具了,我又想把它纳入武器范畴:

class Broom : CleaningTool, IWeapon
{
    double IWeapon.Damage { get { return 42.0; } }
}

interface IWeapon
{
    double Damage { get; }
}

static class IWeaponExtensions
{
    public static void Attack(this IWeapon @this, ITarget target)
    {
        target.Hitpoint -= @this.Damage;
    }
}

当我有一次给小伙伴们填一个坑的时候用了[Obsolete("This property is duplicated with XXX",true)]的时候 我的小伙伴们都惊呆了

想不起来C#有哪些称得上奇技淫巧的了。

不过印象比较深的是13年的NDC (Norwegian Developers Conference)上,C# in Depth的作者Jon Skeet做了一个"Abusing C#“的演讲。

视频地址:vimeo.com/68320506

简介:

We've all seen bad code. Code worthy of the Daily WTF. Code which makes us wonder how products ever ship, let alone work. Bad code is boring. Evil code is entirely different. It's bending a language in ways that would make the designers weep. It's code which you stare at and swear that it can't possibly work... until you see how it does.

I've got some evil code. I'll show it to you. You'll wish I hadn't.


没有赞,还是挑一个最简单的例子。

class BasicDemo
{
        static void Main(string[] args)
        {
            var funky = new[] { "hello", "world", "how", "are", "you" };
            var query = funky.Evil() - "world" + "today" 
                        & (x => x.Length == 5)
                        | (x => x.ToUpper());

            Console.WriteLine(query * 3);

            var xor1 = new[] { "foo", "bar", "baz" }.Evil();
            var xor2 = new[] { "qux", "bar" }.Evil();
            Console.WriteLine(xor1 ^ xor2);
        }
}

输出结果是:

HELLO, TODAY, HELLO, TODAY, HELLO, TODAY
foo, baz, qux

猜猜为啥有这样的结果?答案会在评论里。

© COPYRIGHT BY i How And Why.com 2015