标题令人困惑.让我澄清一下:
我想提供依赖于参数的事件,以便观察者可以决定在特定"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)
您需要使用包含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,然后订阅者可以检查它并决定如何处理它.
我刚刚开始使用Rx框架,它很棒.我想这可能就是你要找的东西.
http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx
订阅和取消订阅在框架中处理.它被称为LINQ to events.它是IEnumerable的"数学对偶".
干杯,-jc
我认为,对于.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教程.
| 归档时间: |
|
| 查看次数: |
1401 次 |
| 最近记录: |