动态创建静态泛型委托

时间:2018-07-09 07:10:34

标签: c# generics static delegates

需要帮助来动态创建静态泛型委托! 我需要使用Execute方法来订阅事件,在该事件中必须有对原始订阅方法“ subscriber”的调用。 代码:

    /// <summary> Event subscriber </summary>
    public static class EventSubscriber
    {
     public static bool SubscribeEvent<T>(this object source, string eventName, EventHandler<T> subscriber, int executeMaxCount = 1)
     {
        var eventInfo = source.GetType().GetEvents().FirstOrDefault(p => string.Compare(p.Name, eventName, StringComparison.InvariantCultureIgnoreCase) == 0);
        if (eventInfo == null)
            return false;

        var method = eventInfo.EventHandlerType.GetMethod("Invoke");
        if (method == null)
            return false;

        var prameters = method.GetParameters();
        if (prameters.Length != 2 && prameters[1].GetType() != typeof(T))
            return false;

        eventInfo.AddEventHandler(source, 
        /* Dynamically create generic delegate like 
        (sender, e) => Execute(eventName, sender, e )

        */
        );

      return true;
     }

     private static void Execute<T>(string eventName, object sender, T e )
     {


     }

    }

非常感谢!

1 个答案:

答案 0 :(得分:0)

    /// <summary> Dynamically create delegate </summary>
    /// <param name="className">Event handler class name</param>
    /// <param name="eventName">Event name</param>
    /// <returns>Delegate</returns>
    private static Delegate CreateDelegate(Type className, string eventName)
    {
        try
        {
            var codeProvider = new CSharpCodeProvider();
            var compilerParameters = new CompilerParameters
            {
                GenerateExecutable = false,
                GenerateInMemory = true,
            };

            var assemblies = className.Assembly.GetReferencedAssemblies().ToList();
            assemblies= assemblies.Union(typeof(EventSubscriber).Assembly.GetReferencedAssemblies()).ToList();
            var assemblyLocations = assemblies.Select(a => Assembly.ReflectionOnlyLoad(a.FullName).Location).ToList();
            // Type where event handler
            assemblyLocations.Add(className.Assembly.Location);
            // Type where I'm
            assemblyLocations.Add(typeof(EventSubscriber).Assembly.Location);
            compilerParameters.ReferencedAssemblies.AddRange(assemblyLocations.ToArray());

            // Dynamic part generated from User text(code)
            var executable = string.Format(@"namespace {0} {{ public static class PrivateExecutor{{ public static {1} Create() {{"
                                           + "{1} _result = (sender, args) => Subscriber.Execute(\"{2}\", sender, args);return _result;}}}}}}",
                                           typeof(EventSubscriber).Namespace,
                                           className.FullName,
                                           eventName);

            // Try to compile
            var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, executable);
            // Check compiler errors
            if(compilerResults.Errors.OfType<CompilerError>().Count(e => !e.IsWarning) > 0)
            {
                var errors = new StringBuilder(string.Empty);
                foreach(var err in compilerResults.Errors.OfType<CompilerError>())
                    errors.AppendFormat("{0} ", err.ErrorText);
                throw new ArgumentException(string.Format("Handler : [{0}]. Event : [{1}]. Error : [{2}]", className, eventName, errors).Trim());
            }

            // Get executable method
            var methinfo = compilerResults.CompiledAssembly.GetType(string.Format("{0}.PrivateExecutor", typeof(EventSubscriber).Namespace)).GetMethod("Create");
            return  (Delegate)methinfo.Invoke(null, null);
        }
        catch(Exception ex)
        {
            throw new ArgumentException(string.Format("{0}{1}", ex.Message, ex.InnerException).Trim());
        }
    }