如何调用Generic Predicates的集合?

时间:2014-11-30 09:41:05

标签: c#

我的设置

我有一个存储组件集合的实体类:

public class Entity
{
    public Dictionary<Type, IComponent> Components { get; set; }
}

组件是实现IComponent的任何类,例如Position,Orientation等。

我有一个Filter类,它存储一组条件,这些条件基本上只是谓词:

public class Filter
{
    public Dictionary<Type, MulticastDelegate> Conditions;

    public Filter()
    {
        Conditions = new Dictionary<Type, MulticastDelegate>();
    }

    public void Add<T>(Predicate<T> predicate) where T : class, IComponent
    {
        Conditions.Add(typeof(T), predicate);
    }
}

我的问题

我要做的是允许创建一个具有不同组件的不同条件(谓词)的过滤器。我想编写一个方法,为其组件都符合条件的任何实体返回true。

到目前为止我有什么

public bool IsMatchFor(Entity entity)
{
    foreach (IComponent component in entity.Components.Values)
    {
        if (Conditions.ContainsKey(component.GetType()))
        // There is a both a Condition in the Filter and a Component in the Entity that match up based on Type. 
        // Now check to see if the Condition is satisfied by the Component
        {
            Type genericPredicate = typeof(Predicate<>);
            Type[] typeArgs = { component.GetType() };
            Type constructedGenericPredicate = genericPredicate.MakeGenericType(typeArgs);
            Predicate<IComponent> predicateInstance = (Predicate<IComponent>)Activator.CreateInstance(constructedGenericPredicate, new object[] { component, Conditions[component.GetType()].Method });

            if (!predicateInstance.Invoke(component))
            {
                return false;
            }
        }
    }

    return true;
}

我遇到的错误

但是我收到错误。基本上我似乎无法构建必要的谓词。有更简单的方法吗?

Test method Tests.Utilities.FilterTests.IsMatchFor_WithASingleConditionThatMatchesEntity_ReturnsTrue threw exception: 
System.MissingMethodException: Constructor on type 'System.Predicate`1[[Tests.TestSupportClasses.ComponentType1, Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found.
Result StackTrace:  
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, Object[] args)
   at Entropy.Utilities.Filter.IsMatchFor(Entity entity) in c:\git\Entropy\Source\Utilities\Filter.cs:line 54
   at Tests.Utilities.FilterTests.IsMatchFor_WithASingleConditionThatMatchesEntity_ReturnsTrue() in c:\git\Entropy\Tests\Utilities\FilterTests.cs:line 128

一个用例来说明为什么这比看起来更复杂

我希望能够编写以下代码:

_filter.Add(typeof(ComponentType1), (Predicate<IComponent>)(new Predicate<ComponentType1>(c => c.BoolProperty)));
Assert.IsTrue(_filter.IsMatchFor(_entities[0]));

基本上通过使用通用谓词,我能够让编辑器帮助我创建一个条件。但是上面的行在编译时会失败,因为Predicate(Of IComponent)不是从Predicate(Of ComponentType1)继承的,即使ComponentType1实现了IComponent。

1 个答案:

答案 0 :(得分:0)

看起来你真正需要的是Dictionary<Type, Predicate<IComponent>>,而不是一般持有MulticastDelegate

public Dictionary<Type, Predicate<IComponent>> Conditions;

当宣布这种方式时,您根本不需要使用反射,只需轻松地从字典中检索Predicate<IComponent>

public bool IsMatchFor(Entity entity)
{
    foreach (IComponent component in entity.Components.Values)
    {
        Predicate<IComponent> componentPredicate;
        if (Conditions.TryGetValue(component.GetType(), out componentPredicate))
        {
            return componentPredicate(component);
        }
    }

    return false;
}