4

私は暇なときにオブジェクト検証フレームワークを作成して、いくつかのことを学び、学校のプロジェクトに使用するかもしれません。

私は一般的な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クラスのプロパティの1つの値であり、任意のタイプにすることができます。

Validate<T>プロパティが設定されるたびにメソッドが呼び出されます。

問題は、クラスのルールのリストにあります。具体的にはList<Rule<?>>上記の行。特定のクラスのすべてのルールを同じリストに保存したいと思います。

残念ながら、C#にはJavaのようなジェネリック型のワイルドカードがありません。

これはどのようにすればよいですか?

Tの代わりにオブジェクトを利用する非ジェネリックインターフェイスまたは基本クラスは機能する可能性がありますがIsBroken、非ジェネリックルールではなくジェネリックルールのメソッドをどのように呼び出すのでしょうか?

4

3 に答える 3

5

私はあなたのルールをクラスobject内に保存し、特定のタイプに一致するルールを見つけるために使用します。 ExampleEnumerable.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();
    }
}
于 2012-08-25T21:02:19.937 に答える
3

このようなものが必要な場合は、インターフェースまたは非ジェネリック基本クラスを使用します。たとえば、次のようなインターフェイスを作成できます。

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>;
}
于 2012-08-25T20:42:57.347 に答える
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
        }
    );
}

かなり醜いですが、動作します。これが他の誰かを助けることができることを願っています。

于 2012-08-26T03:02:44.840 に答える