c# - 如何调用通用谓词的集合?

标签 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。

最佳答案

看起来您真正需要的是 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;
}

关于c# - 如何调用通用谓词的集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27211908/

相关文章:

c# - 使用 MVVM 在 WPF 中设置焦点

c# - Visual Studio 调试器如何决定可以使用 Text/XML/HTML Visualizer 查看哪些值?

c# - 使用装饰器复制 UI 元素

c# - LINQ 中的动态新字段

c# - 多个 if 语句或 else-if 语句

c# - cefsharp 位置更改事件 C#

c# - DataGridView 控件的至少一列没有单元格模板

c# - AutoResetEvent澄清

c# - 文本框输入键事件在 WPF 中不起作用

c# - 如何将此 C# lambda 表达式转换为 VB.Net?