C#-一种干净/高效的方法来过滤某些类实例字段

时间:2018-07-22 16:37:51

标签: c# data-structures reflection event-handling filtering

我正在尝试使用C#滚动事件处理系统-在我的情况下,它是用于Unity中的游戏,但它足够抽象,可以应用于任何系统。

单例类“ EventManager”具有专用的Dictionary(System.Type,Dictionary(long,EventListener))__listener,以及用于注册,注销和ThrowEvent(EventInfo ei)的公共方法。 字典的键是从EventInfo派生的类型,因此将有EventInfoFoo,EventInfoBar等键,并且这些键不一定具有相同的字段。

我还希望只能侦听这些从EventInfo派生的类中的特定条件,例如“仅在ei.CreatureType == Animal时触发”或“在1到5之间的position.x”。

我有一个使用Reflection的可行解决方案,但是其性能还不够好。我的下一个想法是让此过滤器成为注册侦听器的类所传递的委托方法,但是由于我希望几乎所有(如果不是全部)过滤器均是相等/范围检查,因此我想知道是否有一种更干净的处理方式。

以下是相关的课程:

EventListener:

public class EventListener {

public Dictionary<string, string> eventFilter;
public delegate void eventHandler(EventInfo ei);

public eventHandler Eh;

public EventListener( eventHandler evH,Dictionary<string, string> filter)
    {
    Eh= evH;
    eventFilter = filter;
    }}

EventInfo:

public  class EventInfo  {
    public Object Caller;
    public EventInfo (Object __caller)
    {
        Caller = __caller;        
    }
    public EventInfo()
    { Caller = null; }
}
public class EventInfoExample : EventInfo
{
    public int Testint;
    public EventInfoExample(Object __caller)
{
    Caller = __caller;
}
}

EventManager:

公共类EventManager:MonoBehaviour {

private static EventManager __em;
public static EventManager Em
{
    get  { return EventManager.__em; }
}

private Dictionary<System.Type,Dictionary<long, EventListener>> __listeners;    
private long __idcounter = 1;

private long getNewID()
{
    long __ret = __idcounter;
    __idcounter++;
    return __ret;
}

//true on let through , false on block
private bool __doFilter(Dictionary<string,string>eventFilter , EventInfo ei)
{
    // if no filters, accept
    if (eventFilter == null || eventFilter.Count < 1)
        return true;

    System.Type __eit = ei.GetType();
    FieldInfo[] __fields = ei.GetType().GetFields();
    List<string> __fieldlist = __fields.Select(f => f.Name).ToList();

    foreach (KeyValuePair<string,string> kvp in eventFilter)
    {
        if (__fieldlist.Contains(kvp.Key) == false)
            Debug.LogError("Fieldlist for " + __eit.ToString() + " does not contain a field named " + kvp.Key);

        //this is what we are filtering for 
        //TODO add support for operators, for now its just == 
        if (__eit.GetField(kvp.Key).GetValue(ei).ToString() != kvp.Value)
            return false;
    }
    return true;

}

public Object ThrowEvent(EventInfo ei)
{
    Debug.Assert(__listeners != null);
    Debug.Assert(ei != null);

    if (__listeners.ContainsKey(ei.GetType()) == false)
        return null;

    //call all 
     foreach ( KeyValuePair<long,EventListener>  __kvp2 in __listeners[ei.GetType()])
        {              
            // apply listener filters         
            if (__doFilter(__kvp2.Value.eventFilter , ei))
            {
                Debug.Log("Invoking ID " + __kvp2.Key.ToString() + " for " + ei.GetType().ToString());
                __kvp2.Value.Eh(ei);
            }                    
        }     

    return null;
}

public long Register(System.Type eventType,EventListener el)
{
    Debug.Assert(eventType.IsSubclassOf(typeof(EventInfo)));
    Debug.Assert(el != null);

    Debug.Assert(__listeners != null);

    // if we dont have a key for this type, create new dict, then add to dict 
    if (__listeners.ContainsKey(eventType) == false)
        __listeners.Add(eventType, new Dictionary<long, EventListener>());

    long __newID = getNewID();
    //add to list
    __listeners[eventType].Add(__newID, el);
    return __newID;    
}

public bool Unregister(long ID)
{
    return true;
}

// Use this for initialization
void Start () {
    // pop singleton
    EventManager.__em = this;       
}


// Update is called once per frame
void Update () {      
}}

0 个答案:

没有答案