有没有办法在C#(或一些变通方法)中创建索引事件?

maf*_*afu 17 c# events

标题令人困惑.让我澄清一下:

我想提供依赖于参数的事件,以便观察者可以决定在特定"id"发生某些事件时接收事件.它可能看起来像这样:

public event EventHandler Foo (string id);
Run Code Online (Sandbox Code Playgroud)

我知道这种语法在.NET 3.5中是错误的,我也知道这个想法引入了额外的问题(例如,我们如何管理取消订阅?).

我该如何规避这个问题?我想过使用类似的东西:

public EventHandler Foo (string id);
Run Code Online (Sandbox Code Playgroud)

这至少是合法的语法,可以工作,但它对我来说仍然不是很好.

编辑:不是要求将参数传递给回调函数.我的想法更像是这样的:

class Bleh
{
    public event EventHandler Foo (string index);

    private void RaiseEvents() // this is called by a timer or whatever
    {
        Foo["asdf"] (this, EventArgs.Empty); // raises event for all subscribers of Foo with a parameter of "asdf"
        Foo["97"] (this, EventArgs.Empty); // same for all "97"-subscribers
        // above syntax is pure fiction, obviously
    }
}

// subscribe for asdf events via:
Bleh x = new Bleh ();
x.Foo["asdf"] += (s, e) => {};
Run Code Online (Sandbox Code Playgroud)

解释
既然你可能想知道我为什么要这样做,我会解释我的情况.我有一个类提供某些对象的位置(每个对象由一些ID字符串标识).

event EventHandler<PositionChangedEventArgs>我想为每个对象(由索引访问)创建一个事件,而不是为任何位置更改提供一个事件,因此观察者只能侦听特定ID的事件.

Jef*_*Cyr 16

你可以这样做:

public class Foo
{
    public class Bar
    {
        public event EventHandler PositionChanged;

        internal void RaisePositionChanged()
        {
            var handler = PositionChanged;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }

    private Dictionary<string, Bar> m_objects;

    public Bar this[string id]
    {
        get
        {
            if (!m_objects.ContainsKey(id))
                m_objects.Add(id, new Bar());

            return m_objects[id];
        }
    }

    private void RaisePositionChanged(string id)
    {
        Bar bar;
        if (m_objects.TryGetValue(id, out bar))
            bar.RaisePositionChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后订阅一个事件,就像这样简单:

Foo foo = new Foo();

foo["anId"].PositionChanged += YourHandler;
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 7

您需要使用包含ID的EventArgs派生类,然后使用EventHandler<IdEventArgs>或者其他:

public class IdEventArgs : EventArgs
{
    private readonly string id;
    public string Id { get { return id; } }

    public IdEventArgs(string id)
    {
        this.id = id;
    }
}

public event Eventhandler<IdEventArgs> Foo;
Run Code Online (Sandbox Code Playgroud)

当你举起活动时,你需要创建一个实例IdEventArgs,然后订阅者可以检查它并决定如何处理它.


Mis*_*mes 5

我刚刚开始使用Rx框架,它很棒.我想这可能就是你要找的东西.

http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

订阅和取消订阅在框架中处理.它被称为LINQ to events.它是IEnumerable的"数学对偶".

干杯,-jc


Dan*_*Tao 5

我认为,对于.NET无扩展正好你在找什么.

这个想法是这样的:

首先,定义一个派生自EventArgs并包含所需信息的类(特别是您想到的"索引").像这样的东西:

public class IndexedEventArgs : EventArgs {
    public string Index { get; private set; }

    public IndexedEventArgs(string index) {
        Index = index;
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

接下来,对于将要引发事件的类,使用EventHandler<TEventArgs>您刚刚定义的类实现单个事件.在此类定义中,创建一个实现IObservable如下的对象:

public class ClassWithIndexedEvents {
    public event EventHandler<IndexedEventArgs> IndexedEvent;

    public IObservable Events { get; private set; }

    public ClassWithIndexedEvents() {
        // yeah, this feels a little weird, but it works
        Events = Observable.FromEvent<IndexedEventArgs>(this, "IndexedEvent");
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,在您只想订阅与某个索引匹配的事件的代码中,您可以Events按照与以下方式相同的方式过滤您的属性IEnumerable:

// code mangled to fit without scrolling
public IDisposable CreateSubscription(
    string eventIndex,
    Action<IEvent<IndexedEventArgs>> handler) {

    return Events.Where(e => e.Index == eventIndex).Subscribe(handler);
}
Run Code Online (Sandbox Code Playgroud)

请注意,该Subscribe方法返回一个IDisposable对象; 这是您稍后取消订阅您刚刚订阅的过滤事件的关键.代码非常明显:

var fooSubscription = objectWithIndexedEvents.CreateSubscription(
    "foo",
    e => DoSomething(e)
);

// elsewhere in your code
fooSubscription.Dispose();
Run Code Online (Sandbox Code Playgroud)

*免责声明:我或多或少地记录了Rx如何工作的所有代码; 我没有测试过,因为我没有在我正在使用的机器上安装Rx.我明天可以在另一台机器上检查,以确保它写得正确; 现在它应该至少可以作为一个例子,让你了解Rx如何工作.要了解更多信息,您可以随时在线查找Rx教程.