August 15
今天吃了一个烤肉自助,名字是:Mother's Grill,我立即将其翻译为“妈的(注意语调)烤肉”
August 10
洛杉矶的高速是在太密集了,以及于出口相聚太近,有时候GPS报的结果都没法判断是哪一个出口。
到了后来,即使出对了出口也都疑神疑鬼。
这几天开了900 Miles, 好强悍。从Las Vegas 到洛杉矶,再到San Diego,最后回Vegas。 对于一个驾驶新手来说,真是不容易。
July 06
第一次在美国开车,还挺顺利的。照这个趋势,陪练同事回国以后,我还能正常去公司干活, Hooray~~
June 27
................... Still waiting for Airline's transportation
December 01
C# 4.0 将为C#语言带来大量的强有力的新特性,进一步方便广大开发人员。 其中最重要和最为常用的的可能要算泛型接口和委托的协变和逆变。
何为协变(Covariance)和逆变(Contravariance)呢?
用下面这个例子来说明,有Animal 和Cat两个类,Cat继承自Animal:
public abstract class Animal
{ public string Name {get;set;}}
public class Cat:Animal
{ public string Name {get;set}}
根据里氏代换原则,可以把Cat类型的对象隐式转换为Animal类型的对象,
Animal a = new Cat(){Name=”Cat1”};
上面这一行代码不论在哪一版本的C#中运行都没有问题,下面这个问题则是自.NET 2.0以来困扰着我们,
IEnumerable<Animal> a=null;
IEnumerable<Cat> c = new List<Cat>();
a = c;
这不可能通过编译,因为IEnumerable<Animal> 和 IEnumerable<Cat>毫无关系。现在C# 4.0引入了协变和逆变来解决这个问题,首先来看协变,
有了协变的支持,上面的例子就可以被运行了:
IEnumerable<Cat> c = new List<Cat>{new Cat(){Name=”Cat1”}, new Cat(){Name=”Cat2”}};IEnumerable<Animal> a = c;
这是因为IEnuerable<T>从2.0的IEnumerable<T>变为了4.0的IEnumerable<out T>,也就是支持对类型T的协变。
那么什么是协变和逆变呢呢? 我们知道,.NET中,安全的隐式转换只有子类到基类的转换,我们把这种从子类到基类的类型转换称为协变,反之则称为逆变。协变和逆变只能用于泛型的接口和委托(delegate)中。 C# 4.0引入了out, in关键字用来分别表示协变和逆变。
上面的IEnumerable<out T>即支持类型参数T的协变; Action<in T> 这个泛型代理则支持对T的逆变。
当接口或delegate支持对类型参数T的协变,T只能用于方法或Property的返回值;支持对T的反变时,T只能用于方法的参数,或Property的Set Value。
协变和逆变要注意一下几点:
1. 只有泛型接口和泛型委托支持对类型参数的可变性,泛型类或泛型方法是不支持的。
2. 值类型不参与协变或反变, 不管有无声明in/out。
3. 只有只读属性才允许使用out类型参数,只写属性能够使用in参数。
逆变的一个例子:
Action<Animal> action = (a) => Console.WriteLine(a.Name);
Action<Cat> catAct = action; //From parent class –> child class
catAct(new Cat());
注意, .NET 4.0中,Action<T>已经变为了Action<in T>, 以及其他类似的委托。
上面的例子可能还比较容易理解,那下面这个需要多费一点脑细胞 加上多动手实验一下才可以理解了。
考虑这个例子:
IEnumerable<Cat> a = new List<Cat> {new Cat(){Name="Cat1"}, new Cat(){Name="Cat2"}};IEnumerable<Animal> b = a;
Action<Animal> action = (an) => Console.WriteLine(an.Name);
a.AsParallel().ForAll(action);
a.AsParallel()返回的是ParallelQuery,是IEnumerable<T>的子类,它的方法ForAll接收的参数是Action<in T>, 而IEnumerable的声明是IEnumerable<out T>。简化来看就是:
delegate void Action<in T>(T arg);
public interface IEnumerable<out T>
{ public void ForAll(Action<T> action);
}
怪了,明明是out修饰T,应该是协变,那么T只能用于方法的返回值,怎么变到参数里面去了。 一步一步来考虑这个问题:
因为IEnumerable<out T>支持对T的协变,那么IEnumerable<Cat>可以隐式转换为IEnumerable<Animal>, 当IEnumerable<Animal>调用ForAll时,会传入一个Action<Animal>做参数, 那么需要Action<Animal>能够转换为Action<Cat>才能满足调用的需要, 而这个方向的转换则是逆变。
所以, 当一个接口需要对参数类型T支持协变,那么它的方法的参数类型需要支持对T的逆变;反之,当一个接口支持对类型T的逆变,那么接口中方法的参数类型都必须支持对T协变。 当然,如果是父类和子类,这个是可以满足,如果加入了方法参数中加入了泛型的接口或委托时,就要多多注意了。
返回类型和参数类型不同,当接口支持对T协变或逆变时,接口方法的返回类型必须支持对T同样方向的协变或逆变。
November 24
在WPF 3.x中, XAML中如果需要引用.NET Primitive类型的对象的话,需要首先声明Namespace,例如
<s:String xmlns:s="clr-namespace:System;assembly=mscorlib">Foobar</s:String>
在XAML 2009 (WPF 4.0)中,它已经内置的支持了这些类型,简化了XAML代码的编写。
String, Char, Single, Double, Boolean, Byte, Int16, Int32, Int64, Decimal, Object, TimeSpan, Array都被支持。
可以使用<x:String>Hello WPF</x:String>这样的方式来进行对象的定义。
November 23
松动方程提供了10多种不同的公式,用来给WPF的动画增加更加真实和平滑的效果(来自Silverlight 3.0)。
11种内置的Easing functions如下所示:
<BackEase Amplitude='1' EasingMode='EaseIn' />
<BounceEase Bounces='3' Bounciness='2' EasingMode='EaseIn'/>
<CircleEase EasingMode='EaseIn' />
<CubicEase EasingMode='EaseIn' />
<ElasticEase EasingMode='EaseIn' Oscillations='3' Springiness='3' />
<ExponentialEase EasingMode='EaseIn' />
<PowerEase EasingMode='EaseIn' Power='3'/>
<QuadraticEase EasingMode='EaseIn' />
<QuarticEase EasingMode='EaseIn' />
<QuinticEase EasingMode='EaseIn' />
<SineEase EasingMode='EaseIn' />
这里是Easing方程的源代码
November 20
C# 4.0 增加了dynamic关键字, dynamic关键字修饰的变量类型会是后期绑定的(late binding), 这极大的增强了C#的动态特性。
下面是一个简单的例子:
dynamic mycustomer = new Customer() {Name = “YW”, Age=29};
Console.WriteLine(mycustomer.Name);
这看起来和var 关键字类似,但是两者的原理完全不同。 var关键字在编译时就被替换为真实类型,而dynamic则是运行时才会去查看对应的对象是否具有"Name”属性。
配合ExpandoObject,可以具有更加动态的效果,例如为对象动态增加方法和成员,并在随后进行调用:
dynamic ProductList = new ExpandoObject();
ProductList.Items = new List<int>();
ProductList.Add = new Action<object>((i)=>ProductList.Items.Add(i));
//和Javascript很像,对吧。 不过javascript在定义方法的表达式时可以写this.成员来引用目标实例的内部成员,这里却不可以,只能显示指定实例。
ProductList.Add(1);
Console.WriteLine(ProductList.Items[0]);
非常动态是吧,配合ExpandoObject, dynamic变态可以动态的增加方法和成员。 不过有时候,也不是很好用,比如,从一个配置文件读取了某个操作,想要动态的设置方法名和方法,这个方法名按照上面的方式就没有办法写了。 今天看到Bill Wagner写的Method Bag,这个问题得到了一定程度的解决, Bill只写了部分代码,我在这里完整的写一个小例子:
public class MethodBag:DynamicObject
{
private Dictionary<string, MethodDescription> methods = new Dictionary<string, MethodDescription>();
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
if (!methods.ContainsKey(binder.Name))
return false;
MethodDescription method = methods[binder.Name];
if (method.NumberOfParameters != args.Length)
return false;
result = method.Invoke(args);
return true;
}
public void SetMethod(string name, Expression<Action> lambda)
{
if (!methods.ContainsKey(name))
{
methods.Add(name, new ActionDescription() { target = lambda });
}
}
public void SetMethod<T>(string name, Expression<Func<T>> lambda)
{
if (!methods.ContainsKey(name))
{
methods.Add(name, new FuncDescription<T>() { target = lambda });
}
}
}
public abstract class MethodDescription
{
internal abstract int NumberOfParameters
{
get;
}
internal Expression target
{
get;
set;
}
internal abstract object Invoke(object[] parms);
}
public class ActionDescription : MethodDescription
{
internal override int NumberOfParameters
{
get
{
return (target as Expression<Action>).Parameters.Count;
}
}
internal override object Invoke(object[] parms)
{
var target2 = target as Expression<Action>;
target2.Compile().Invoke();
return null;
}
}
public class FuncDescription<T> : MethodDescription
{
internal override int NumberOfParameters
{
get
{
return (target as Expression<Func<T>>).Parameters.Count;
}
}
internal override object Invoke(object[] parms)
{
var target2 = target as Expression<Func<T>>;
T result = target2.Compile().Invoke();
return result;
}
}
调用时,一定要用dynamic关键字转换一次:
var bag = new MethodBag();
bag.SetMethod("Output", () => 1 + 1);
dynamic dispatcher = bag;
Console.WriteLine(dispatcher.Output());
这个例子只包含了Action和Func<T>的Expression, 剩下的可以自行补充.
November 18
尽日暮乡关
望月冷千山
负瑶光 九天宿 映山高水流长
纵雨乱风寒
忆上青云峦
共千鸟夕唱
衣裳雪 清风袖 舞挥洒苍茫
笛晚萦江
仙踪渺 路何方 烟帘影 尘上霜
春掬兰 盈满堂 夏灵荷 倚湖船
秋琼叶 绒飞扬 冬雪枝 宜梅香
人影北 潮汐南 扑萤火 梦正酣
烟尽敛 闲遍看 六朝湖山
步凝驻听 浮生远 离人唱
耽隐成仙 人影淡 不问红尘乱
千秋山水 仙路情长 人难忘