【问题标题】:Generics and events泛型和事件
【发布时间】:2013-05-05 00:44:15
【问题描述】:

我正在制作一款游戏,我正在尝试为对象创建一种处理彼此碰撞的方法。我想做类似的事情:

//Imaginary C#

public SomethingThatCollides()
{
    CollisionEvent<ObjectA> += CollisionWithObjA;
    CollisionEvent<ObjectB> += CollisionWithObjB;
}

void CollisionWithObjA(ObjectA other)
{
    //Do something
}
void CollisionWithObjB(ObjectB other)
{
    //Do something else
}

例如,当CollisionEvent&lt;ObjectA&gt; 被引发(可能是通过一些碰撞检查代码)时,应该调用CollisionWithObjACollisionWithObjB 相同;当检测到与 ObjectB 的冲突时,它将引发 CollisionEvent&lt;ObjectB&gt; 事件,从而导致 CollisionWithObjB 被调用。

这样的事情可能吗?

【问题讨论】:

  • 很难理解您要做什么。你的意思是当碰撞发生时你会调用'SomethingThatCollides'方法?请提供更多解释
  • @Andrew:如果我有objA、objB和objC,它们都可以和它们全部碰撞??? AB、AC、BC会有碰撞方法吗?
  • 或者它是一个主对象,它与所有其他对象发生碰撞,对彼此之间的碰撞没有任何处理?
  • 可能有,但在这种情况下,我只有 AB 和 AC,没有 BC

标签: c# events generics


【解决方案1】:

事情是这样的,如果类是通用的并且它有静态字段,它可以像字典一样工作,键是类型

public class Something {
    public class EventsHolder<T> 
    {
       static event Action<T> CollideEvent;
    }

    public void AddEvent<T>(Action<T> collisionEvent) 
    {
      EventsHolder<T>.CollideEvent = collisionEvent;
    }

    public void RaiseCollision<T>(T Obj)
    {
      var Event = EventsHolder<T>.CollideEvent;
      if (Event != null) Event(Obj);
    }
}

缺点是它使用了可能不合适的静态字段。 在这种情况下,您可以使用 @Daniel 发布的代码。

【讨论】:

  • 嗯,听起来很有趣,但我无法从 EventsHolder 外部呼叫 EventsHolder&lt;T&gt;.CollideEvent,我该如何解决这个问题?
  • 在EventsHolder中创建一个CallEvent静态方法来调用事件。现在在RaiseCollision 你调用那个方法。 (我编辑了答案,但必须等待某人修改)
  • @AndrewSun 只需公开方法即可。
【解决方案2】:

您无法真正创建这样的通用事件。我建议您创建一个特殊的事件参数类,该类还封装了碰撞对象并在事件处理程序方法中检查其类型:

public class CollisionEventArgs : EventArgs {
  public object Object {
    get; private set;
  }
  // ...
}

你需要一个特殊的调度方法来使用它:

class SomethingThatCollides {

  public SomethingThatCollides(CollisionManager cm) {
    cm.CollisionEvent += CollisionWithObj;
  }

  void CollisionWithObj(object sender, CollisionEventArgs args) {
    if (args.Object is ObjectA) {
      CollisionWithObjA((ObjectA)args.Object);
    }
    else if (args.Object is ObjectB) {
      CollisionWithObjB((ObjectB)args.Object);
    }
  }

  // ...
}

或者,您可以尝试通过双重调度解决此问题,而不使用 C# 事件。查看wikipedia 中的碰撞示例。

【讨论】:

  • 重点是创建一个单独的方法来处理每次碰撞,而无需进行不必要的装箱和类型检查。真的没有办法吗?
  • 查看维基百科上的double-dispatching
【解决方案3】:

这很难看,但是...您可以按类型拥有事件字典:

Dictionary<Type, object> MyEventsByType;

event Action<A> CollisionEventA;
event Action<B> CollisionEventB;
event Action<C> COllisionEventC;

void Initialize()
{
    MyEventsByType = new Dictionary<Type, object>();

    MyEventsByType.Add(typeof(A), CollisionEventA);
    MyEventsByType.Add(typeof(B), CollisionEventB);
    MyEventsByType.Add(typeof(C), CollisionEventC);
}

void RaiseCollision<T>(T Obj)
{
    Action<T> Event = (Action<T>)MyEventsByType[typeof(T)];
    if (Event != null) Event(Obj);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多