2012-08-12 61 views
1

使用TypeGeneratorDuplexChannelFactory <反射接口>

public class TypeGenerator 
    { 
     /// <summary> 
     /// internal cache for already generated types 
     /// </summary> 
     private static Dictionary<Type, Type> asyncTypeCache = new Dictionary<Type, Type>();  

     /// <summary> 
     /// provides a cache for the modules 
     /// </summary> 
     private static Dictionary<string, ModuleBuilder> moduleBuilderCache = new Dictionary<string, ModuleBuilder>(); 

     /// <summary> 
     /// Generates the Async version of the TSync type. 
     /// the generate type repects the AsyncPattern and it is already decorated with attributes for WCF operations 
     /// </summary> 
     /// <typeparam name="TSync">The Sync version of type</typeparam> 
     /// <returns>A type that is the Async version of the TSync type, that implements the AsyncPattern for WCF</returns> 
     public Type GenerateAsyncInterfaceFor<TSync>() where TSync : class 
     { 
      Type syncType = typeof(TSync); 

      if (asyncTypeCache.ContainsKey(syncType)) return asyncTypeCache[syncType]; 

      if (!syncType.IsInterface) throw new InvalidOperationException("Only interface type could be transformed"); 

      var asynchAssemblyName = string.Format("{0}.Async", syncType.Namespace); 

      TypeBuilder typeBuilder = 
       GetModuleBuilder(asynchAssemblyName) 
       .DefineType(
        string.Format("{0}.Async.{1}", syncType.Namespace, syncType.Name), 
        (syncType.IsPublic ? TypeAttributes.Public : 0) | 
        TypeAttributes.Abstract | 
        TypeAttributes.Interface); 

      foreach (var method in syncType.GetAllInterfaceMethods()) 
      { 
       AddBeginAsynchVersionForMethod(typeBuilder, method, @"http://tempuri.org"); 
       AddEndAsynchVersionForMethod(typeBuilder, method); 
      } 

      var serviceContractConstructor = typeof(ServiceContractAttribute).GetConstructor(new Type[0]); 
      var attribuiteBuilder = 
       new CustomAttributeBuilder(
        serviceContractConstructor, 
        new object[0]); 

      typeBuilder.SetCustomAttribute(attribuiteBuilder); 

      Type asyncType = typeBuilder.CreateType(); 

      asyncTypeCache.Add(syncType, asyncType); 
      return asyncType; 
     } 

     /// <summary> 
     /// Creates a End verison of a sync method, that implements the AsyncPattern 
     /// </summary> 
     /// <param name="typeBuilder">the tipebuilder where the type is being building</param> 
     /// <param name="method">information about the sync version of the method</param> 
     private void AddEndAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method) 
     { 
      string endMethodName = string.Format("End{0}", method.Name); 

      var parameters = 
       method.GetParameters() 
       .Select(x => 
        new 
        { 
         Type = x.ParameterType, 
         Name = x.Name, 
         Attributes = x.Attributes, 
        }) 
       .ToList(); 

      parameters.Add(
       new 
       { 
        Type = typeof(IAsyncResult), 
        Name = "asyncResult", 
        Attributes = ParameterAttributes.None, 
       }); 

      var methodBuilder = 
       typeBuilder 
       .DefineMethod(
        endMethodName, 
        method.Attributes, 
        method.CallingConvention, 
        method.ReturnType, 
        parameters.Select(x => x.Type).ToArray()); 

      for (int i = 0; i < parameters.Count(); i++) 
      { 
       var parameter = parameters[i]; 
       methodBuilder.DefineParameter(i + 1, parameter.Attributes, parameter.Name);    
      } 
     } 

     /// <summary> 
     /// Creates a Begin verison of a sync method, that implements the AsyncPattern 
     /// </summary> 
     /// <param name="typeBuilder">the tipebuilder where the type is being building</param> 
     /// <param name="method">information about the sync version of the method</param> 
     private void AddBeginAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method, string nameSpace) 
     { 
      string beginMethodName = string.Format("Begin{0}", method.Name); 

      var parametersTypeList = method.GetParameters().Select(x => x.ParameterType).ToList(); 
      var parametersNameList = method.GetParameters().Select(x => x.Name).ToList(); 
      var parametersAttributeList = method.GetParameters().Select(x => x.Attributes).ToList(); 

      parametersTypeList.Add(typeof(AsyncCallback)); 
      parametersAttributeList.Add(ParameterAttributes.None); 
      parametersNameList.Add("callBack"); 

      parametersTypeList.Add(typeof(object)); 
      parametersAttributeList.Add(ParameterAttributes.None); 
      parametersNameList.Add("statusObject"); 

      var methodBuilder = 
       typeBuilder 
       .DefineMethod(
        beginMethodName, 
        method.Attributes, 
        method.CallingConvention, 
        typeof(IAsyncResult), 
        parametersTypeList.ToArray()); 

      for (int i = 0; i < parametersTypeList.Count(); i++) 
      { 
       methodBuilder.DefineParameter(i + 1, parametersAttributeList[i], parametersNameList[i]); 
      } 

      var operationContractConstructor = typeof(OperationContractAttribute).GetConstructor(new Type[0]); 
      var asynchPatternProperty = typeof(OperationContractAttribute).GetProperty("AsyncPattern"); 

      var actionProperty = typeof(OperationContractAttribute).GetProperty("Action"); 
      var actionValue = string.Format("{0}/{1}/{2}", nameSpace, method.DeclaringType.Name, method.Name); 

      var replyActionProperty = typeof(OperationContractAttribute).GetProperty("ReplyAction"); 
      var replyActionValue = string.Format("{0}/{1}/{2}Response", nameSpace, method.DeclaringType.Name, method.Name); 

      var attribuiteBuilder = 
       new CustomAttributeBuilder(
        operationContractConstructor, 
        new object[0], 
        new[] { asynchPatternProperty, actionProperty, replyActionProperty }, 
        new object[] { true, actionValue, replyActionValue }); 



      methodBuilder.SetCustomAttribute(attribuiteBuilder); 
     } 

     /// <summary> 
     /// provides a ModelBuilder with the required assembly name 
     /// </summary> 
     /// <param name="requiredAssemblyName">the assembly name for where the type will be generated in</param> 
     /// <returns>a model builder</returns> 
     /// <remarks>in this version the model builder is not cached, it could be interesting to generate all the types in the same assembly by caching the model builder</remarks> 
     private ModuleBuilder GetModuleBuilder(string requiredAssemblyName) 
     { 
      if (moduleBuilderCache.ContainsKey(requiredAssemblyName)) 
      { 
       return moduleBuilderCache[requiredAssemblyName]; 
      } 

      AssemblyName assemblyName = new AssemblyName(requiredAssemblyName); 
      AssemblyBuilder assemblyBuilder = 
       AppDomain.CurrentDomain.DefineDynamicAssembly(
        assemblyName, 
        AssemblyBuilderAccess.Run); 

      ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); 

      moduleBuilderCache[requiredAssemblyName] = moduleBuilder; 

      return moduleBuilder; 
     } 
    } 

TypeExtentions

public static class TypeExtensions 
    { 
     /// <summary> 
     /// extracts all the methods fromthe given interface type and from all the inherited ones too 
     /// </summary> 
     /// <param name="type">the type fromwhich extracts all the methods</param> 
     /// <returns>list of MemberInfo representing the methods</returns> 
     public static IEnumerable<MethodInfo> GetAllInterfaceMethods(this Type type) 
     { 

      IEnumerable<MethodInfo> methods = type.GetMethods(); 
      foreach (var subType in type.GetInterfaces()) 
      { 
       methods = methods.Union(GetAllInterfaceMethods(subType)); 
      } 
      return methods; 
     } 
    } 

我是能夠將同步接口轉換爲異步之一。

如何使用DuplexChannelFactory預定義反射異步接口?

var myInterface = new TypeGenerator () . GenerateAsyncInterfaceFor<mySynchronousInterface> (); 

var Client = new DuplexChannelFactory<myInterface> (new InstanceContext (new myClass ()) , "myConfiguration"); 

,我發現了以下問題:

類型或命名空間名稱「MyInterface的」找不到(你 缺少using指令或程序集引用?)

我想編碼一箇中層WCF接口。

+0

您可以發佈這是代碼請造成錯誤。 – 2012-08-13 07:53:56

+0

@hugh更多詳細信息已添加 – 2012-08-15 17:41:27

回答

2

您正在使用的語法是用於編譯時鍵入,當然,您所做的類型是在運行時生成的,因此它不起作用。這是可能的,但。 How to: Examine and Instantiate Generic Types with Reflection

下面的代碼將如何看(我假設myClass的是已經與源代碼中定義,如果沒有這純粹是另一個Activator.CreateInstance呼叫)

Type t = typeof(DuplexChannelFactory<>); 
Type typedDuplexChannelFactory = t.MakeGenericType(new Type[]{myInterface}); 
var Client = Activator.CreateInstance(typedDuplexChannelFactory, new object[]{new InstanceContext (new myClass ()) , "myConfiguration"});