我正在嘗試為我的專案構建一個規則檢查器,它回圈瀏覽規則串列,如果其中任何一個具有 true 標志,則回傳我。下面是我撰寫的代碼作為我正在嘗試做的事情的示例(不是實際代碼,請忽略最終未觀察到的最佳實踐或細節)。
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);
}
}
這樣做的重點是將來對具有一個或多個介面的不同“MainClass”使用相同的規則檢查器,并且可以重用該規則或添加新的規則,例如具有自己的觸發邏輯的“模塊”。
上面的代碼不起作用,因為當我呼叫通用 voids ( UpdateMe<ICounterValued>and UpdateMe<ITimeValued>) 資料值時,無法訪問我在介面 ( CounterValue, CounterLimit, ElapsedTime, TimeLimit) 中定義的屬性。
我假設這種空泛型方法存在一些轉換或介面問題;我沒有必要使用泛型,但我沒有找到更聰明的解決方案;我tryied與代表作為引數的東西UpdateMe在Rule類,但沒有什么能與不同型別的引數進行擴展,讓規則檢查通過傳遞的實體呼叫于一身MyMainClass的每一個。
感謝andavace 的任何建議。
uj5u.com熱心網友回復:
以這種方式構建(你的方法)對我來說更有意義:
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);
}
}
用你的方法,我無法弄清楚為什么 X 類會有一個規則串列,一個人可能會將 Y 類傳遞給它;他們適用的規則和課程在我的腦海中聯系在一起......因此我在構建時建立了這個鏈接
..但即便如此我也不知道我是否會這樣做
我想我更有可能做這樣的事情:
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);
}
}
uj5u.com熱心網友回復:
我找到了一個似乎有效的解決方案,并且與我一直在尋找的方法相近。@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派生類上的方法,將檢查實體作為泛型傳遞object。任何擴展的類都Rule可以IsTriggered在內部使用顯式強制轉換來實作其規則邏輯覆寫,然后最終開始檢查。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/366533.html
