Feb 16, 2010

Covariant/Contravariant Support for generic interface .net 4.0

The introduction of generic in .net makes covariant/contravariant support a very interesting topic. Now .net 4, there are some support for generic interface. But covariant and contravariant for generic class is still not supported with good reason, so you can not write the following code in .net 2 and .net 4

[TestMethod]
public void no_covariant_support_for_generic_class()
{
    //can not be compiled
    List<object> list = GetListOfString();
    //if support, what if use write
    list[0] = 1; //this is not secure

}

public List<string> GetListOfString()
{
    return new List<string>();
}

[TestMethod]
public void no_contravariant_support_generic_class()
{
    //can not be compiled
    Process(new List<string>());
}

public void Process(List<object> input)
{
    //if this is support, what if user write
    input[0] = 1; //this is not secure
    
}

There reason of not supporting covariant or contravariant is that .net need to support type safety. But as long as, we can restrict user to use object in type safe fashion, we should allow it. .NET 4 provide covariant and contravariant support for generic interface and delegate by using "in" and "out" to decorate type parameter so that the interface can be only use the type parameter in "in" or "out" fashion. Here is an example

interface IHouse<out T>
{
   T Checkout();
}

In the above example, T can be only appear in the return type position. So you can compile the following code.

If you want write the following code, then will be a compiler error like "Invalid variance: The type parameter'T' must be contravariantly valid on 'Checkin(T)'. 'T' is covariant

interface IHouse<out T>
{
   T Checkout();
   void CheckIn(T input);
}

To fix this error, we can add new contravariant type parameter using "in", like the following, and change the client code as well. The K type parameter will only appear at the input parameter position.

interface IHouse<out T, in K>
{
   T Checkout();
   void CheckIn(K input);
}


class House<T, K> : IHouse<T, K>
{
   public T Checkout()
   {
     return default(T);
   }

   public void Checkin(K input)
   {
       Console.WriteLine(input.GetType());
   }
}

IHouse<string, object> x = new House<string, object>();
IHouse<object, string> y = x;
object rtn = y.Checkout();
y.Checkin("hello"); //it actually call x.Checkout(object input), which is fine

Ok, so now what is the big deal of the covariant and contravariant. The short answer is that, it make it possible for you to write code you think it make sense but you couldn't before .net 4. So now you can write the code below which is not possible in .net 2. Here is covariant example in .net 4


//in .net 2, you have to write
IEnumerable<string> list = new List<string> { "1", "2", "3" };
//in .net 4, you can write the following because of the "out" keyword, it support covariant
//public interface IEnumerable<out T> : IEnumerable
IEnumerable<object> list = new List<string> { "1", "2", "3" };

//but you still can not write this in .net 4,  
//Covariance and contravariance in generic type parameters are supported for reference types, //but they are not supported for value types.
IEnumerable<object> list = new List<string> { 1, 2, 3 };

compiled time support for Covariant and Contravariant in .net 2.0


In .net 2.0, A delegate can be associated with a named method, this facility provide support for covariant and contravariant as the following sample code shows.

        delegate void ProcessString(string item);
        delegate object GetObject();

        void RunObject(object item)
        {
            Console.WriteLine(item);
        }

        string RetrieveString()
        {
            return string.Empty;
        }

        [TestMethod]
        public void delegate_shortcut_suport_contraVariant()
        {
            //delegate with derived type parameter input <--(accept) method with base type parameter input
            ProcessString processString = this.RunObject;
            processString("string");
            //-->
            RunObject("string");
        }

        [TestMethod]
        public void delegate_shortcut_support_coVariant()
        {
            //delegate with base type output <--(accept) method with derived type output 
            GetObject getObject = this.RetrieveString;
            object returnValue = getObject();
            //-->
            object returnValue2 = this.RetrieveString();
        }

Feb 15, 2010

The semantics of c# interface

We all use interface construct in c#. Recently I came across the Haack's blog Interface Inheritance Esoterica, I decided to find out more. So I write a very simple example like below

public interface IAnimal
    {
        void Walk();
    }

    public interface IBird : IAnimal
    {
        void Fly();
    }

    public class Bird : IBird 
    {
        void IBird.Fly()
        {
            throw new NotImplementedException();
        }

        void IAnimal.Walk()
        {
            throw new NotImplementedException();
        }
    }

Then I use ILDASM to examine the IL generated, the Bird class actually implement two interface,


//Bird IL
.class public auto ansi beforefieldinit DemoInterface.Bird
       extends [mscorlib]System.Object
       implements DemoInterface.IBird,
                  DemoInterface.IAnimal
{
} // end of class DemoInterface.Bird

//
.class interface public abstract auto ansi DemoInterface.IBird
       implements DemoInterface.IAnimal
{
} // end of class DemoInterface.IBird


We can see that the Walk is not a member of IBird, the semantics here is the class that implement IBird, should also implement IAnimal. So I change my code to be the following

public interface IAnimal
    {
        void Walk();
    }

    public interface IBird //: IAnimal
    {
        void Fly();
    }

    public class Bird : IBird , IAnimal
    {
        void IBird.Fly()
        {
            throw new NotImplementedException();
        }

        void IAnimal.Walk()
        {
            throw new NotImplementedException();
        }
    }

This time the generated IL for Bird is exactly the same as previous code. The only difference is that IBird does not "implement" IAniaml. In the first example, the semantics of Bird implementing IBird is as following


  1. The class is an IBird (or we can say it has gene.) Even the IBird interface has no member it still has semantics, System.Web.UI.INamingContainer it is an example.
  2. The Bird class is an IAnimal
  3. The Bird class implements IBird member Fly()
  4. IAniaml's member is not the member of IBird, but IBird support IAnimal's memeber
  5. The class that implements IBird, also need to implements IAnimal.
  6. The Bird class implements IAniaml member Walk(), because of previous semantics

The the original intention of interface is contract, and a contact can be a composite, which means a contract can be a combination of other contract(s).

Feb 12, 2010

Get started with EntityFramework 4

We have the following option to using EntityFramework4


  • Using designer
    • Model First

      We can design model first , then generate the sql for the model, use the sql to generate the database, and then connect the model to the database. The process of sql gereration is customizable. You change this workflow (process) and the template of the sql, these file are located at C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen.
      ASO.NET team blog has an article about this a approach.

    • Database First

      This is a classic approach. You have your database in the first place, and generate model based on that.


    Since you have use the designer, you have other customization options that are related to code generation from the model created by designer. But default designer use a Code generation strategy call "Default". If you model file name is "model.edmx", the strategy generate a cs file "model.cs" file, and the code generate the ObjectContext, and other entities, and so forth. The entities


    [EdmEntityTypeAttribute(NamespaceName="CrmModel", Name="Post")]
    [Serializable()]
    [DataContractAttribute(IsReference=true)]
    public partial class Post : EntityObject
    { ... }
    

    Since EF4 use t4 to generate code, you can customized the t4 to customized the code generation by right clicking the designer and adding code generation item. When you add code generation item, this will turn off the default code generation strategy. Your model.cs file will be empty.


    There are a couple code generation item available now. When you add an item a t4 file (*.tt) is added to the project. You can customize the tt file as want.


  • Use code only
    Feature CTP Walkthrough: Code Only for the Entity Framework (Updated)