簡體   English   中英

同一列表中的多個泛型類型並調用它們的方法

[英]Multiple generic types in same list and calling their methods

我在業余時間制作一個對象驗證框架來學習一些東西,並可能將它用於一些學校項目。

我有我的通用Rule類,它看起來像這樣:

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方法而不是非泛型方法呢?

我將您的規則存儲為Example類中的object ,並使用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();
    }
}

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

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

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

然后創建一個接口列表:

private List<IRule> MyRules;

如果要從界面轉換為通用easy,可以添加擴展方法:

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

我嘗試了一些東西,並且我發現了一些適合我需求的東西。 我有一個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
        }
    );
}

這很難看,但它確實有效。 希望這可以幫助其他人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM