【发布时间】:2021-11-13 00:17:24
【问题描述】:
我正在尝试为我的项目构建一个规则检查器,该检查器在规则列表中循环,如果其中任何一个的标志为真,则返回我。 下面是我作为示例编写的代码(不是实际代码,请忽略最终未观察到的最佳实践或细节)。
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public interface ICounterValued {
int CounterValue {get;}
int CounterLimit {get;}
}
public interface ITimeValued {
float ElapsedTime {get;}
float TimeLimit {get;}
}
public class MyMainClass : ICounterValued , ITimeValued {
// Counter data
private int _counterValue = 0;
private int _counterLimit = 10;
// Time data
private float _elapsedTime = 0;
private float _timeLimit = 10f;
// ICounterValued
public int CounterValue => _counterValue;
public int CounterLimit => _counterLimit;
// ITimeValued
public float ElapsedTime => _elapsedTime;
public float TimeLimit => _timeLimit;
public RuleChecker ruleChecker;
public void InitializeMe(){
ruleChecker = new RuleChecker();
ruleChecker.rules.Add( new TimeRule() );
ruleChecker.rules.Add( new CounterRule() );
}
public void UpdateRuleChecker(){
ruleChecker.CheckRules<MyMainClass>( this );
}
public bool NeedToStop(){
return ruleChecker.SomeRuleTriggered();
}
}
public class RuleChecker {
public List<Rule> rules = new List<Rule>();
public void CheckRules<T>( T data ){
rules.ForEach( x => x.UpdateMe<T>(data) );
}
public bool SomeRuleTriggered(){
return rules.Any( x => x.IsTriggered() );
}
}
public abstract class Rule {
protected bool _triggered;
public virtual bool IsTriggered() => _triggered;
// check logic that will set the _triggered flag to true
public abstract void UpdateMe<T>( T data );
}
public class TimeRule : Rule {
public override void UpdateMe<ITimeValued>( ITimeValued data ){
_triggered = (data.ElapsedTime >= data.TimeLimit);
}
}
public class CounterRule : Rule {
public override void UpdateMe<ICounterValued>( ICounterValued data ){
_triggered = (data.CounterValue >= data.CounterLimit);
}
}
这样做的目的是在未来对具有一个或多个接口的不同“MainClasses”使用相同的规则检查器,并且可以重用这些规则或添加新的规则,如具有自己的触发逻辑的“模块”。
上面的代码不起作用,因为当我调用通用 void(UpdateMe<ICounterValued> 和 UpdateMe<ITimeValued>)时,数据值无法访问我在接口内定义的属性(CounterValue,CounterLimit,ElapsedTime, TimeLimit)。
我假设这种 void 泛型方法存在一些转换或接口问题;我没有必要使用泛型,但我没有找到更聪明的解决方案;我已经在Rule 类中尝试了将代表作为UpdateMe 的参数的一些东西,但是没有任何东西可以用不同的类型参数进行扩展,并让规则检查器通过为每个参数传递MyMainClass 的实例来调用所有内容。
感谢 andavace 的任何建议。
【问题讨论】:
-
你得到的确切错误是什么,错误到底在哪里?
-
我想,但我不确定问题是你在
Rule.UpdateMe<T>中对T没有限制,允许访问属性。我想我可以创建一个基本接口public interface IValued { int Value { get; } int Limit { get; } },然后显式实现ICounterValued和ITimeValued(暂时忽略int/float)。到目前为止我找不到魔法酱。我希望这个漫无边际的帮助 -
@Flydog57 错误为
'ITimeValued' does not contain a definition for 'ElapsedTime' and no accessible extension method 'ElapsedTime' accepting a first argument of type 'ITimeValued' could be found (are you missing a using directive or an assembly reference?),所有其他属性都相同。如果我总是知道界面内将包含什么类型的数据,则可以完成您的解决方案。我正在尝试实现的实际用途,例如,使用更复杂的接口,例如:``` public interface ITimer { AdvancedTimer Timer { get; } } ``` -
是的,我复制了你的代码并试图让它编译,得到了同样的错误。这是因为
T缺少约束。你不能在T上调用某些东西,除非T以允许调用发生的方式受到限制。我现在想已经太晚了,但你的问题让我很感兴趣。一旦我离开,我可能会想出一个解决方案。 -
@Flydog57 我认为你是对的,
UpdateMe的覆盖使data属性被视为通用T值,而不是被覆盖的接口类型。泛型解决方案看起来太有限,无法做如此不均匀的事情;也许与返回bool的代表的事情是可行的。
标签: c# generics interface delegates extends