1

TypeGeneratorクラスの使用

   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インターフェイスをコーディングしようとしています。

4

1 に答える 1

2

使用している構文はコンパイル時の型付け用です。もちろん、作成している型は実行時に生成されるため、機能しません。しかし、それは可能です。 方法:リフレクションを使用してジェネリック型を調べてインスタンス化する

コードは次のようになります(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"});
于 2012-08-21T01:18:20.957 に答える