2012-08-25 30 views
4

我在業餘時間製作一個對象驗證框架來學習一些東西,並可能將它用於一些學校項目。同一列表中的多個泛型類型並調用它們的方法

我有我的通用規則類,它看起來是這樣的:

class Rule<T> 
{ 
    string propertyName; 
    Func<T, bool> ruleLambda; 

    bool IsBroken(T value) 
    { 
     return ruleLambda(value); 
    } 
} 

將被驗證看起來有點像這樣的對象:

class Example 
{ 
    List<Rule<?>> MyRules; // can take all types of rules 

    List<Rule<T>> Validate<T>(string propertyName, T value) 
    { 
     List<Rule<T>> brokenRules = new List<Rule<T>>(); 
     foreach (Rule rule in MyRules.Where(r => r.propertyName == propertyName)) 
     { 
      if (rule.IsBroken(value)) 
       brokenRules.Add(rule); 
     } 
     return brokenRules; 
    } 
} 

T value論證會其中一個Example類的屬性值,可以是任何類型的值。

只要設置了屬性,就會調用Validate<T>方法。

問題在於班級的規則列表。具體是上面的List<Rule<?>>行。我想將給定類的所有規則存儲在同一個列表中。

唉,C#沒有像Java一樣的泛型類型的通配符。

我該怎麼做?

使用對象而不是T的非泛型接口或基類可以工作,但我該如何調用泛型規則的IsBroken方法而不是非泛型方法?

+4

定義一個接口IRule,帶有非通用接口,例如'布爾IsBroken(物體)',並有'規則:IRule',並有'列表'..好吧,它不是很漂亮,但它*工作,是我見過的最好的。 – 2012-08-25 20:34:55

回答

1

我已經嘗試了一些東西,我發現一些作品非常好滿足我的需求。我有一個抽象基規則類Rule<T>繼承,與通用IsBroken方法:

abstract class Rule 
{ 
    string propertyName; 
    Func<object, bool> objectRule; 

    bool IsBroken<T>(T value) 
    { 
     Rule<T> rule = this as Rule<T>; 
     if (rule == null) 
      return objectRule(value); 

     return rule.IsBroken(value); 
    } 
} 

正如你所看到的,我嘗試使用泛型類型參數在IsBroken方法對基類轉換爲它的通用同行。

此外,在創建一個Rule<T>實例時,我送一個Func<object, bool>其基類的受保護的構造:

public Rule(string propertyName, Func<T, bool> ruleLambda) 
    : base(propertyName, ConvertToObjectFunc(ruleLambda)) 
{ 
} 

與轉換方法看起來像這樣:

static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func) 
{ 
    return new Func<object, bool>(o => func((T)o)); 
} 

但是,如果它能夠不會把o改成T型,它會崩潰。所以我寫了這個......東西:

static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func) 
{ 
    return new Func<object, bool> 
    (
     o => 
     { 
      try 
      { 
       T obj = (T)o; 
       return func(obj); 
      } 
      catch { return true; } // rule is broken by default 
     } 
    ); 
} 

這是非常醜陋的,但它的作品。希望這可以幫助其他人。

2

在我需要類似這樣的情況下,我使用接口或非泛型基類。例如,你可以創建一個接口:

public interface IRule 
{ 
    //non-generic properties & methods 
} 

public class Rule<T> : IRule 
{ 
    //implementation 
} 

然後創建接口的列表:

private List<IRule> MyRules; 

如果你想從接口轉換成通用的方便,你可以添加一個擴展方法:

public static Rule<T> ToGeneric<T>(this IRule rule) 
{ 
    return rule as Rule<T>; 
} 
4

我會存儲您的規則objectExample類中,並使用Enumerable.OfType<T>來找到一個給定的匹配規則類型:

class Example 
{ 
    private List<object> rules; 

    List<Rule<T>> Validate<T>(string propertyName, T value) 
    { 
     return this.rules.OfType<Rule<T>>() 
      .Where(r => r.PropertyName == propertyName && r.IsBroken(value)) 
      .ToList(); 
    } 
} 
相關問題