Wang's profile曾少你的,你已在别处都得到PhotosBlogLists Tools Help

曾少你的,你已在别处都得到

Windows Media Player

August 15

烤肉自助

今天吃了一个烤肉自助,名字是:Mother's Grill,我立即将其翻译为“妈的(注意语调)烤肉” 
August 10

GPS在洛杉矶都不太好使啊


洛杉矶的高速是在太密集了,以及于出口相聚太近,有时候GPS报的结果都没法判断是哪一个出口。

到了后来,即使出对了出口也都疑神疑鬼。

这几天开了900 Miles, 好强悍。从Las Vegas 到洛杉矶,再到San Diego,最后回Vegas。 对于一个驾驶新手来说,真是不容易。

Map picture

July 06

First time Driving in U.S

第一次在美国开车,还挺顺利的。照这个趋势,陪练同事回国以后,我还能正常去公司干活, Hooray~~
June 27

Arrived Las Vegas, but where are our Baggages?

...................   Still waiting for Airline's transportation
December 01

C# 4.0 协变和逆变

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

What’s new In XAML 2009(WPF 4.0 beta 2) 之 XAML支持.NET基本类型

在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

What’s new In XAML 2009(WPF 4.0 beta 2) 之 松动方程 (Easing function)

松动方程提供了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方程的源代码

What’s new In XAML 2009(WPF 4.0 beta 2) 之 XAML中的方法调用

 

  WPF 4.0 beta2随着.NET Framework 4.0beta2一起发布, .NET Framework 4.0的脚本越来越近了,作为一个WPF和Silverlight的爱好者,同时也是工作技能的我来说,需要对WPF 4.0的新功能有一些了解。

在读了http://blogs.msdn.com/llobo/archive/tags/New+WPF+4+features/default.aspx 以后,我谋生了将这些新特性变成文字的想法,用来记录自己学习的过程,同时也希望对有幸看见我博客的人有一定的帮助。 这里部分是翻译,部分是自己的代码和观点。

在NETFX 4.0中, XAML格式的相关功能将被独立抽取出来放在了System.Xaml Assembly中, 由此可见XAML在整个.NET Framework中的地位得到了提升,同时也减小了WPF和XAML之间的耦合。

本文主要内容是将如何在XAML之中调用方法。 这依赖于XAML 2009中新的IXamlNameResolver, 它可以用来帮助通过名称在XAML中查找命名元素。

示例锁需要的类代码:

public class School
   {
       public Students Class { get; set; }

       public Student Topper { get; set; }
   }

   [ContentProperty("Class")]
   public class Students
   {
       private List<Student> class1 = new List<Student>();

       public Students()
       {
       }

       public List<Student> Class
       {
           get
           {
               return class1;
           }
       }

       /// <summary>
       /// Gets a Student object with highest marks in Class collection
       /// </summary>
       /// <returns>Student with highest marks</returns>
       /// <remarks>This method will be called from XAML using markup extension</remarks>
       public Student GetTopper()
       {
           Student topper = null;

           foreach (Student student in Class)
           {
               if (topper == null)
               {
                   topper = student;
                   continue;
               }

               if (student.Marks > topper.Marks)
               {
                   topper = student;
               }
           }

           return topper;
       }
   }

   [RuntimeNameProperty("Name")]
   public class Student
   {
       public string Name { get; set; }
       public int Marks { get; set; }
   }

下面是示例中的XAML代码:

<School 
    xmlns="clr-namespace:CallingMethodOnNamedObject;assembly=CallingMethodOnNamedObject"
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    Topper="{Call students.GetTopper}"
    >
    <School.Class>
        <Students x:Name="students">
            <Student Name="Audrey" Marks="90" />
            <Student Name="Bill" Marks="95" />
            <Student Name="Claire" Marks="100" />
            <Student Name="Dan" Marks="85" />
            <Student Name="Evan" Marks="99" />
        </Students>
    </School.Class>
   </School>

熟悉XAML的人大概是知道{Call XXX}这种写法意味着有一个Markup Extension, Call 并非XAML 2009内置的功能,需要手动编写代码来实现CallExtension.

public class CallExtension : MarkupExtension
   {
       public string Expression { get; set; }

       public CallExtension()
       {
       }

       public CallExtension(string expression)
       {
           this.Expression = expression;
       }

 

        /// <summary>
        /// Must implement this method for new markup extension
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            IXamlNameResolver nameResolver = (IXamlNameResolver)serviceProvider.GetService(typeof(IXamlNameResolver));
            if (nameResolver == null)
            {
                throw new InvalidOperationException("Missing NameResolver");
            }

            // Split the object name and method name apart
            string[] parts = Expression.Split(new char[] { '.' });

            // 仅支持objectname.methodname这种形式的调用, 你可以把它扩展到其他形式的方法调用
            if (parts.Length != 2)
            {
                throw new InvalidOperationException("Unsupported format. Only \"objectname.methodname\" is supported");
            }

            // 解析对象名称(指XMAL中,x:Name对应的对象)
            object instance = nameResolver.Resolve(parts[0]);
            if (instance == null)
            {
                string[] names = new string[] { parts[0] };
                instance = nameResolver.GetFixupToken(names);
                return instance;
            }
            else
            {
                return Invoke(instance, parts[1]);
            }
        }

       /// <summary>
       /// 调用方法
       /// </summary>
       /// <param name="instance">Object on which to invoke the method</param>
       /// <param name="methodName">Name of the method to invoke</param>
       /// <returns></returns>
       private object Invoke(object instance, string methodName)
       {
           MethodInfo methodInfo = instance.GetType().GetMethod(methodName);

           if (methodInfo == null)
           {
               throw new InvalidOperationException("Method " + methodName + " not found");
           }

           return methodInfo.Invoke(instance, null);
       }
   }

November 20

C# 4.0 动态特性

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

仙尘谣

尽日暮乡关
望月冷千山
负瑶光 九天宿 映山高水流长
纵雨乱风寒
忆上青云峦
共千鸟夕唱
衣裳雪 清风袖 舞挥洒苍茫
笛晚萦江
仙踪渺 路何方 烟帘影 尘上霜
春掬兰 盈满堂 夏灵荷 倚湖船
秋琼叶 绒飞扬 冬雪枝 宜梅香
人影北 潮汐南 扑萤火 梦正酣
烟尽敛 闲遍看 六朝湖山
步凝驻听 浮生远 离人唱
耽隐成仙 人影淡 不问红尘乱
千秋山水 仙路情长 人难忘