在拥有该函数的对象被实例化之前分配`delegate`函数

时间:2016-05-05 23:39:13

标签: c# .net generics dynamic delegates

我正在开发一个系统,其中Watcher可以设置为对Event感兴趣,如果Action Event,则调用Action传递正确的类型。

现在Event在调用时需要有关Action的信息。

在下面的代码中,我使用委托作为Watcher属性(不是.NET方式的属性,只是字段/成员/等等......)在设置{时传递Event函数{1}}。

当然,代码的问题在于 // Step3 ,当我这样做时,字段TheEvent为空。只有Watcher通过Event后才会知道。

如何告知Watcher ActionEvent被分配之前Event获取namespace ConsoleApplication1 { using System; internal class Program { static void Main(string[] args) { //Step1: choose the IEvent: NumericEvent //Step2: create Watcher<NumbericEvent> Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>(); //Step3: Choose and add an action aWatcher.TheAction = new AlphaAction(); //Step3 bind the ActionProperties aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1; aWatcher.TheAction.AnActionPropertyB = aWatcher.TheEvent.GetProperty2; //Step4 Bind the event NumericEvent anEvent = new NumericEvent(); aWatcher.Call(anEvent); } } internal class AlphaAction { internal delegate string ActionPropertyA(); internal delegate int ActionPropertyB(); internal ActionPropertyA AnActionPropertyA; internal ActionPropertyB AnActionPropertyB; internal string ActionPropertyC; public void Run() { Console.Write(AnActionPropertyA.Invoke()); Console.Write(AnActionPropertyB.Invoke()); } } internal interface IEvent { } internal class NumericEvent:IEvent { internal string EventProperty1 = "Property1"; internal int EventProperty2 = 2; internal string GetProperty1() { return EventProperty1; } internal int GetProperty2() { return EventProperty2; } } internal class Watcher<T> where T:IEvent { internal NumericEvent TheEvent; internal AlphaAction TheAction; internal void Call(IEvent anEvent) { TheEvent = (NumericEvent)anEvent; TheAction.Run(); } } } 所需的属性?

internal class Program
{
    static void Main(string[] args)
    {

        //Step1: choose the IEvent: NumericEvent
        //Step2: create Watcher<NumbericEvent>
        Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>();

        //Step3: Choose and add an action
        aWatcher.TheAction = new AlphaAction();

        //Step3 bind the ActionProperties

        MethodInfo method1 = typeof(NumericEvent).GetMethod("GetProperty1");
        aWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1);

        MethodInfo method2 = typeof(NumericEvent).GetMethod("GetProperty2");
        aWatcher.TheAction.AnActionPropertyB = (AlphaAction.ActionPropertyB)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyB), aWatcher.TheEvent, method2);

        //Step4 an event is created and passed to the Watcher
        NumericEvent anEvent = new NumericEvent("bla",3);
        if (aWatcher.GType() == anEvent.GetType())
            aWatcher.Call(anEvent);

    }
}

internal abstract class BaseAction
{
    public abstract void Run();
}

internal class AlphaAction: BaseAction
{
    internal delegate string ActionPropertyA();
    internal delegate int ActionPropertyB();

    internal ActionPropertyA AnActionPropertyA;
    internal ActionPropertyB AnActionPropertyB;
    internal string ActionPropertyC;

    public override void Run()
    {
        Console.Write(AnActionPropertyA.Invoke());
        Console.Write(AnActionPropertyB.Invoke());
    }
}


internal interface IEvent
{
}

internal class NumericEvent : IEvent
{
    private readonly string _eventProperty1;
    private readonly int _eventProperty2;

    public NumericEvent(string p1, int p2)
    {
        _eventProperty1 = p1;
        _eventProperty2 = p2;
    }

    public string GetProperty1()
    {
        return _eventProperty1;
    }
    public int GetProperty2()
    {
        return _eventProperty2;
    }

}

internal class Watcher<T> where T:IEvent
{
    internal T TheEvent;
    internal AlphaAction TheAction;

    internal Type GType()
    {
        return typeof(T);
    }

    internal void Call(IEvent anEvent)
    {
        TheEvent = (T)anEvent;
        TheAction.Run();
    }
}

可能需要采取完全不同的方法,但我希望这可以解决问题和期望的结果。

更新

我使用Delegate.CreateDelegate(https://msdn.microsoft.com/en-us/library/s3860fy3.aspx)做了一些操作,但它仍然不太正确,因为如果分配时为null,则将其视为静态:

命名空间ConsoleApplication1 {     使用系统;     使用System.Reflection;

#include <linux/slab.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include "sched.h"
#include "sched1.h"


/* This function is called when the module t is loaded. */
 int process_init(void)   
 {
   printk(KERN_INFO "lOADING  MODULE \n");
   printk(KERN_INFO "PID \t PPID \t PNAME \t SIZE \n");

  struct task_struct *task;
  for_each_process(task)
  {
    printk(KERN_INFO "%d \t %d\t %s \t %d \n",   task->pid,task->ppid,task->comm,task->sz);
   }

        return 0;
  }

}

3 个答案:

答案 0 :(得分:1)

如果我理解你的需要,那么你可以使用Galasoft's MVVM Light Toolkit

重点如下:

  • 定义消息类型,例如SomeMessage
  • 注册您希望收到通知的此类邮件。
  • 可以通过发送SomeMessage
  • 的实例来引发“事件”
  • 将执行为此消息注册的所有操作。

我们举一个例子:

// First you create the message with the needed properties.
public SomeMessage
{
    public string Content { get; set; }
}

// Then at some places you register for listening to this type of message
Messenger.Default.Register<SomeMessage>(
    this,
    message => YourMethodThatProcessesTheMessage(message)
);

// Your method knows the exact type of the message
// So you can access all the properties of the message
private void YourMethodThatProcessesTheMessage(SomeMessage message)
{
    Console.WriteLine(message.Content);
}

// At another place you can simply send a message to all the listeners
var message = new SomeMessage() { Content = "something" };
Messenger.Default.Send<SomeMessage>(message);

答案 1 :(得分:1)

如果我理解你正确,你想要做以下事情:有一个Watcher类来查找特定事件,当它被传递给类时,应该触发一个动作,并且该事件应该作为参数。

我不完全理解为什么你需要这个洞的东西以及为什么你按照你的方式设置东西但这里有一个简单的实现可能会有所帮助:

internal interface IEvent { }

internal class Watcher<T> where T : IEvent
{
    internal Action<T> Action;

    public void On(IEvent evnt)
    {
        if (evnt is T) Action?.Invoke((T) evnt);
    }
}

您可以通过实施IEvent来创建新事件,并且可以注册当观察者通过设置Action字段注册指定类型的操作时应触发的操作。 e.g。

var watcher = new Watcher<NumberEvent>();
watcher.Action += e => Console.WriteLine($"Got a number: {e.Number}");

watcher.On(new StringEvent { Text = "hello"});
watcher.On(new NumberEvent { Number = 1337});

何时定义

internal class NumberEvent : IEvent
{
    internal int Number;
}

internal class StringEvent : IEvent
{
    internal string Text;
}

如果我没有正确理解你的问题(并且很有可能我没有),请解释你的程序应该做什么。

以下是您实施的一些想法/问题:

  • 您正在创建一个通用观察者类(Watcher<T>),但T未在观察者内部使用。您可能希望将NumericEvent替换为T,并检查指定的IEvent是否属于T类型(或您的NumericEvent)。您的编码使IEvent过时了。
  • C#具有属性string EventProperty { get; }。您不必制作GetProperty1()方法(您的字段也是内部的,为什么要使用该方法?)
  • 只需向活动提供活动,不要尝试将活动热线连接到活动。

答案 2 :(得分:1)

您的代码存在的问题是aWatcher.TheEvent行中的aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1;(以及更新后的代码aWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1);)。

由于创建代理时aWatcher.TheEventnull,因此代理始终使用null。您不关心以后在行TheEvent = (NumericEvent)anEvent;中分配事件。

要实现这一点,您需要让代表知道将来会有一个课程。这就是我将如何做到的,但我怀疑这会破坏你想要它如何工作的逻辑。

void Main()
{
    Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>();
    aWatcher.TheAction = new AlphaAction<NumericEvent>();
    aWatcher.TheAction.AnActionPropertyA = ne => ne.GetProperty1();
    aWatcher.TheAction.AnActionPropertyB = ne => ne.GetProperty2();
    NumericEvent anEvent = new NumericEvent("bla", 3);
    if (aWatcher.GType() == anEvent.GetType())
        aWatcher.Call(anEvent);
}

internal abstract class BaseAction<T> where T : IEvent
{
    public abstract void Run(T theEvent);
}

internal class AlphaAction<T> : BaseAction<T> where T : IEvent
{
    internal delegate string ActionPropertyA(T theEvent);
    internal delegate int ActionPropertyB(T theEvent);

    internal ActionPropertyA AnActionPropertyA;
    internal ActionPropertyB AnActionPropertyB;

    public override void Run(T theEvent)
    {
        Console.Write(AnActionPropertyA(theEvent));
        Console.Write(AnActionPropertyB(theEvent));
    }
}

internal interface IEvent
{
}

internal class NumericEvent : IEvent
{
    private readonly string _eventProperty1;
    private readonly int _eventProperty2;

    public NumericEvent(string p1, int p2)
    {
        _eventProperty1 = p1;
        _eventProperty2 = p2;
    }

    public string GetProperty1()
    {
        return _eventProperty1;
    }
    public int GetProperty2()
    {
        return _eventProperty2;
    }
}

internal class Watcher<T> where T : IEvent
{
    internal AlphaAction<T> TheAction;

    internal Type GType()
    {
        return typeof(T);
    }

    internal void Call(T theEvent)
    {
        TheAction.Run(theEvent);
    }
}