我的设置
我有一个存储组件集合的实体类:
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。
答案 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;
}