C# 调用具有不同类型的相同扩展函数作为参数(可能是委托?)
C# call same extended function with different type as parameter (maybe delegates ?)
我正在尝试为我的项目构建一个规则检查器,该检查器循环通过规则列表,如果其中任何一个具有 true 标志,则 return 我。
在我编写的代码下方,作为我正在尝试做的示例(不是实际代码,请忽略最终未观察到的最佳实践或细节)。
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”使用相同的规则检查器,并有可能重用该规则或添加新的规则,如“模块”和他自己的触发逻辑.
上面的代码不起作用,因为当我调用通用 voids(UpdateMe<ICounterValued>
和 UpdateMe<ITimeValued>
)时,数据值无法访问我在接口中定义的属性(CounterValue
, CounterLimit
,ElapsedTime
,TimeLimit
).
我假设这种 void 泛型方法存在一些转换或接口问题;我没有必要使用泛型,但我没有找到更聪明的解决方案;我已经尝试过使用委托作为 Rule
class 中 UpdateMe
的参数,但没有任何东西可以用不同类型的参数扩展,并让规则检查器通过传递实例来调用所有每个 MyMainClass
。
感谢andavace的任何建议。
以这种方式构建(您的方法)对我来说更有意义:
public class RuledClass{
public List<Rule> Rules = new List<Rule>();
public bool AnyViolated(){
return Rules.Any(r => r.IsViolated());
}
}
public class MyMainClass : RuledClass, ICounterValued , ITimeValued {
// Counter data
public int CounterValue {get;set;}
public int CounterLimit {get;set;}
// Time data
public float ElapsedTime {get;set;}
public float TimeLimit {get;set;}
// ICounterValued
public MyMainClass(){
Rules.Add( new TimeRule(this) );
Rules.Add( new CounterRule(this) );
}
}
public abstract class Rule {
public abstract bool IsViolated();
}
public class TimeRule : Rule {
private ITimeValued _thing;
public TimeRule(ITimeValued thing){
_thing = thing;
}
public override bool IsViolated(){
return (_thing.ElapsedTime >= _thing.TimeLimit);
}
}
public class CounterRule : Rule {
private ICounterValued _thing;
public CounterRule(ICounterValued thing){
_thing = thing;
}
public override bool IsViolated(){
return (_thing.CounterValue >= _thing.CounterLimit);
}
}
我想不通,用你的方法,为什么 class X 会有一个规则列表,可以将 class Y 传递给这些规则;规则和它们适用的 class 在我的脑海中是联系在一起的.. 因此我在构建时 link
..但即使那样我也不知道我是否会这样做
我认为我更有可能这样做:
public class RuledClass{
public List<Func<bool>> Rules = new List<Func<bool>>();
public bool AnyViolated(){
return Rules.Any(r => r());
}
}
public class MyMainClass : RuledClass {
// Counter data
public int CounterValue {get;set;}
public int CounterLimit {get;set;}
// Time data
public float ElapsedTime {get;set;}
public float TimeLimit {get;set;}
// ICounterValued
public MyMainClass(){
Rules.Add(()=>ElapsedTime>TimeLimit);
Rules.Add(()=>CounterValue>CounterLimit);
}
}
我找到了一个似乎有效并且接近我所寻找的解决方案。
@Caius Jard 的第一个解决方案也有效,但我认为最好避免将检查实例一直指向规则变量内。
在我的问题中的相同示例代码下方,但更新代码旁边有注释:
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() );
}
// I don't need this anymore, the condition will be checked
// inside SomeRuleTriggered
// public void UpdateRuleChecker(){
// ruleChecker.CheckRules<MyMainClass>( this );
// }
public bool NeedToStop(){
// The instance will be passed as argument
// return ruleChecker.SomeRuleTriggered();
return ruleChecker.SomeRuleTriggered( this );
}
}
public class RuleChecker {
public List<Rule> rules = new List<Rule>();
// As commented above, I don't need to update a stored
// flag in Rule (and direved) anymore
// public void CheckRules<T>( T data ){
// rules.ForEach( x => x.UpdateMe<T>(data) );
// }
// Now the instance will be passed as a generic object and parsed
// inside IsTriggered method
// public bool SomeRuleTriggered(){
// return rules.Any( x => x.IsTriggered() );
// }
public bool SomeRuleTriggered( object target ){
return rules.Any( x => x.IsTriggered( target ) );
}
}
public abstract class Rule {
// No need to update a falg anymore
// protected bool _triggered;
// No need to update a falg anymore
// public virtual bool IsTriggered() => _triggered;
// No need to update a falg anymore
// public abstract void UpdateMe<T>( T data );
public abstract bool IsTriggered( object target );
}
public class TimeRule : Rule {
// No need to update a falg anymore
// public override void UpdateMe<ITimeValued>( ITimeValued data ){
// _triggered = (data.ElapsedTime >= data.TimeLimit);
// }
public override bool IsTriggered( object target ){
ITimeValued target_timed = target as ITimeValued;
if( null == target_timed)
return false;
return (target_timed.ElapsedTime >= target_timed.TimeLimit);
}
}
public class CounterRule : Rule {
// No need to update a falg anymore
// public override void UpdateMe<ICounterValued>( ICounterValued data ){
// _triggered = (data.CounterValue >= data.CounterLimit);
// }
public override bool IsTriggered( object target ){
ICounterValued target_counter = target as ICounterValued;
if( null == target_counter)
return false;
return (target_counter.CounterValue >= target_counter.CounterLimit);
}
}
如您所见,RuleChecker
可以在任何 Rule
派生的 class 上调用该方法,将检查实例作为通用 object
传递。任何扩展 Rule
的 class 都可以实现他的规则逻辑覆盖 IsTriggered
并在内部进行显式转换,然后最终开始检查。
我正在尝试为我的项目构建一个规则检查器,该检查器循环通过规则列表,如果其中任何一个具有 true 标志,则 return 我。 在我编写的代码下方,作为我正在尝试做的示例(不是实际代码,请忽略最终未观察到的最佳实践或细节)。
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”使用相同的规则检查器,并有可能重用该规则或添加新的规则,如“模块”和他自己的触发逻辑.
上面的代码不起作用,因为当我调用通用 voids(UpdateMe<ICounterValued>
和 UpdateMe<ITimeValued>
)时,数据值无法访问我在接口中定义的属性(CounterValue
, CounterLimit
,ElapsedTime
,TimeLimit
).
我假设这种 void 泛型方法存在一些转换或接口问题;我没有必要使用泛型,但我没有找到更聪明的解决方案;我已经尝试过使用委托作为 Rule
class 中 UpdateMe
的参数,但没有任何东西可以用不同类型的参数扩展,并让规则检查器通过传递实例来调用所有每个 MyMainClass
。
感谢andavace的任何建议。
以这种方式构建(您的方法)对我来说更有意义:
public class RuledClass{
public List<Rule> Rules = new List<Rule>();
public bool AnyViolated(){
return Rules.Any(r => r.IsViolated());
}
}
public class MyMainClass : RuledClass, ICounterValued , ITimeValued {
// Counter data
public int CounterValue {get;set;}
public int CounterLimit {get;set;}
// Time data
public float ElapsedTime {get;set;}
public float TimeLimit {get;set;}
// ICounterValued
public MyMainClass(){
Rules.Add( new TimeRule(this) );
Rules.Add( new CounterRule(this) );
}
}
public abstract class Rule {
public abstract bool IsViolated();
}
public class TimeRule : Rule {
private ITimeValued _thing;
public TimeRule(ITimeValued thing){
_thing = thing;
}
public override bool IsViolated(){
return (_thing.ElapsedTime >= _thing.TimeLimit);
}
}
public class CounterRule : Rule {
private ICounterValued _thing;
public CounterRule(ICounterValued thing){
_thing = thing;
}
public override bool IsViolated(){
return (_thing.CounterValue >= _thing.CounterLimit);
}
}
我想不通,用你的方法,为什么 class X 会有一个规则列表,可以将 class Y 传递给这些规则;规则和它们适用的 class 在我的脑海中是联系在一起的.. 因此我在构建时 link
..但即使那样我也不知道我是否会这样做
我认为我更有可能这样做:
public class RuledClass{
public List<Func<bool>> Rules = new List<Func<bool>>();
public bool AnyViolated(){
return Rules.Any(r => r());
}
}
public class MyMainClass : RuledClass {
// Counter data
public int CounterValue {get;set;}
public int CounterLimit {get;set;}
// Time data
public float ElapsedTime {get;set;}
public float TimeLimit {get;set;}
// ICounterValued
public MyMainClass(){
Rules.Add(()=>ElapsedTime>TimeLimit);
Rules.Add(()=>CounterValue>CounterLimit);
}
}
我找到了一个似乎有效并且接近我所寻找的解决方案。 @Caius Jard 的第一个解决方案也有效,但我认为最好避免将检查实例一直指向规则变量内。 在我的问题中的相同示例代码下方,但更新代码旁边有注释:
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() );
}
// I don't need this anymore, the condition will be checked
// inside SomeRuleTriggered
// public void UpdateRuleChecker(){
// ruleChecker.CheckRules<MyMainClass>( this );
// }
public bool NeedToStop(){
// The instance will be passed as argument
// return ruleChecker.SomeRuleTriggered();
return ruleChecker.SomeRuleTriggered( this );
}
}
public class RuleChecker {
public List<Rule> rules = new List<Rule>();
// As commented above, I don't need to update a stored
// flag in Rule (and direved) anymore
// public void CheckRules<T>( T data ){
// rules.ForEach( x => x.UpdateMe<T>(data) );
// }
// Now the instance will be passed as a generic object and parsed
// inside IsTriggered method
// public bool SomeRuleTriggered(){
// return rules.Any( x => x.IsTriggered() );
// }
public bool SomeRuleTriggered( object target ){
return rules.Any( x => x.IsTriggered( target ) );
}
}
public abstract class Rule {
// No need to update a falg anymore
// protected bool _triggered;
// No need to update a falg anymore
// public virtual bool IsTriggered() => _triggered;
// No need to update a falg anymore
// public abstract void UpdateMe<T>( T data );
public abstract bool IsTriggered( object target );
}
public class TimeRule : Rule {
// No need to update a falg anymore
// public override void UpdateMe<ITimeValued>( ITimeValued data ){
// _triggered = (data.ElapsedTime >= data.TimeLimit);
// }
public override bool IsTriggered( object target ){
ITimeValued target_timed = target as ITimeValued;
if( null == target_timed)
return false;
return (target_timed.ElapsedTime >= target_timed.TimeLimit);
}
}
public class CounterRule : Rule {
// No need to update a falg anymore
// public override void UpdateMe<ICounterValued>( ICounterValued data ){
// _triggered = (data.CounterValue >= data.CounterLimit);
// }
public override bool IsTriggered( object target ){
ICounterValued target_counter = target as ICounterValued;
if( null == target_counter)
return false;
return (target_counter.CounterValue >= target_counter.CounterLimit);
}
}
如您所见,RuleChecker
可以在任何 Rule
派生的 class 上调用该方法,将检查实例作为通用 object
传递。任何扩展 Rule
的 class 都可以实现他的规则逻辑覆盖 IsTriggered
并在内部进行显式转换,然后最终开始检查。