运行期多态-function overloading

面试时问到这个问题,印度人术语还挺多。就是重写同名方法嘛,但是调用参数不一样,所以.net 运行环境会根据
参数匹配以及可能的转换情况做匹配。好吧,这也算多态。
http://csharpindepth.com/Articles/General/Overloading.aspx
1. 函数签名只包括入参,不包括出参,如果入参按顺序匹配成功了就会调用,出参不匹配再报错。
2.调用匹配时,overload > override, 子类里的同名overload函数如果参数implicit conversion可以匹配上,则优先于同名override的基类函数的调用,即使基类函数不需要转换也能匹配参数。
阅读(10)

协变与逆变

这个概念很多年前就知道,但是总是学了忘学了忘,还是因为没有从本质上了解它,没有总结好。

首先要定下来一个变字:
Variance refers to how subtyping between more complex types relates to subtyping between their components.。 举个例子就是整个集合(接口,不是类)的继承性和集合中当个元素的继承性之间的关系,或者是delegate(Function和Action这些)和它的入参出参之间的继承关系的传递。
CoVariance就是协(同)变, 所以是component有父子类关系的,连带着把复杂对象也提携成有父子类继承关系了。比如IEnumerable<Cat>是 IEnumerable<Animal>的子类型。于是就可以安全地把子类对象付给父类变量了(变就是允许跨父子关系的变量赋值)。
ContraVariance是逆变,就是Component有父子关系,连带着把复杂对象变成了有子父关系的(反过来的)。例子就是 Action<Cat> 是 Action<Animal> 的父类型。所以可以把Action<Animal>类型的delegate实例给Action<Cat>类型的delegate变量赋值,为下一步的调用做准备。
无论是IEnumerable接口还是Action delegate,或者是这里的泛型类的例子,component的类型都是作为泛型参数指定的,所以c#在指定泛型类参数的添加了一个in/out的泛型参数modifier,专门用来指明这个泛型参数的给它的父结构带来的变化(Variance)方向是协变还是逆变。in是逆变,out是协变
 namespace System.Collections.Generic下的
public interface IEnumerable<out T> : IEnumerable
就可以理解为参数T给IEnumerable<T>带来了协变。
而namespace system下的
public delegate void Action<in T>(T obj);
则说明参数T给Action<T>带来了逆变。实例见上文。
另外要注意,
1. 变只是针对接口,方法,泛型类定义里的参数,从来就不是针对具体的Collection类。
2. 集合接口中也只适用只有只读属性的接口,比如IEnumerable<out T>,不包括IList<T>,因为IList带有非只读方法,可以增加集合元素,所以不支持变。

IList<Animal> animals;
List<Dog> dogs = new List<Dog>();
animals =dogs; //compile error, no CoVariance for IList<T>
animals = dogs.ToArray(); //compile pass,dog array is IList<Dog>, there is no varance here.
animals.Add(new Dog()); //runtime error: ‘Collection was of a fixed size.’ internally, Array doesn’t support Add() as List class do.

最后两行是另一个话题,即Array的实现,根据 https://msdn.microsoft.com/en-us/library/system.array(v=vs.110).aspx
Unlike the classes in the System.Collections namespaces, Array has a fixed capacity. To increase the capacity, you must create a new Array object with the required capacity, copy the elements from the old Array object to the new one, and delete the old Array.(这也是List<T>类的实现)
Starting with the .NET Framework 2.0, the Array class implements the System.Collections.Generic.IList<T>System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IEnumerable<T> generic interfaces. The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class. In addition, there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations). The key thing to be aware of when you cast an array to one of these interfaces is that members which add, insert, or remove elements throw NotSupportedException.

不仅在运行时实现了IList<T>, Array类还静态实现了IList接口,代码是这样实现的:

int IList.Add(object value)
{
throw newNotSupportedException(Environment.GetResourceString(“NotSupported_FixedSizeCollection”));
}
所以System.Array类只是提供了模版代码给[]构造器用,很多接口并没有真正实现。违反了LSP.