各IPersisted
タイプには独自の式があるため、 の側でそれを制約にしIPersisted
ます。これで、ある種のポリモーフィズムができました。
何かのようなもの?
interface IPersisted<T> where T: IPersisted<T>
{
Expression<Func<T, bool>> Predicate { get; }
}
class Repo<T> where T : IPersisted<T>, new()
{
public IQueryable<T> Get()
{
var dummy = new T();
return _queryable.Where(dummy.Predicate);
}
}
class Deletable : IPersisted<Deletable>
{
public Deletable()
{
}
public Expression<Func<Deletable, bool>> Predicate
{
get { return x => !x.IsDeleted; }
}
bool IsDeleted { get; set; }
}
ここで必要なのはある種の静的ポリモーフィズムだと思いますが、C# はそれを提供していないため、式を取得するためだけにダミーのインスタンスを作成する必要があるかもしれません。
デフォルトのコンストラクターがない場合は、に頼ることができますFormatterServices.GetUninitializedObject(t)
。Get
次のようにメソッドを調整できます。
public IQueryable<T> Get()
{
var dummy = (T)FormatterServices.GetUninitializedObject(typeof(T));
return _queryable.Where(dummy.Predicate);
}
おそらく多くの注意事項のうちの2つのことFormatterServices.GetUninitializedObject
:
何も初期化したり、コンストラクターを実行したりしませんが、それは問題にはなりません。
比較的遅いです。インスタンスをキャッシュできるので、大したことではありません:)
class Repo<T> where T : IPersisted<T>
{
//caching mechanism: this is run only once per instance; you can make it
//static if this shud be run only once the entire lifetime of application
readonly T dummy = (T)FormatterServices.GetUninitializedObject(typeof(T));
public IQueryable<T> Get()
{
return _queryable.Where(dummy.Predicate);
}
}
正確な式が重要でない場合は、オブジェクトのインスタンス化を取り除くことができます。何かのようなもの:
interface IPersisted<T> where T: IPersisted<T>
{
Func<T, bool> Predicate { get; }
}
class Repo<T> where T : IPersisted<T>
{
public IQueryable<T> Get()
{
return _queryable.Where(x => x.Predicate(x));
}
}
class Deletable : IPersisted<Deletable>
{
public Func<Deletable, bool> Predicate
{
get { return x => !x.IsDeleted; }
}
}
の元の定義を保持することIPersisted
が重要な場合は、非ジェネリックにすることができます。それがそれほど強く型付けされないかどうかはわかりません。
interface IPersisted
{
Expression<Func<object, bool>> Predicate { get; }
}
class Repo<T> where T : IPersisted
{
public IQueryable<T> Get()
{
return _queryable.Where(dummy.Predicate);
}
}
class Deletable : IPersisted
{
public Expression<Func<object, bool>> Predicate
{
get { return x => !((Deletable)x).IsDeleted; }
}
}
上記のアプローチは、メソッドを使用することでより強く型付けすることができますがIPersisted
、制約が十分である必要はありません。
interface IPersisted
{
Expression<Func<T, bool>> GetPredicate<T>() where T : IPersisted;
}
class Repo<T> where T : IPersisted
{
public IQueryable<T> Get()
{
return _queryable.Where(dummy.GetPredicate<T>());
}
}
class Deletable : IPersisted
{
Expression<Func<T, bool>> IPersisted.GetPredicate<T>() //made it explicit
{
return x => ((Deletable)(object)x).IsDeleted;
}
}
注:クラスPredicate
の外で意味をなさない場合は、実装を明示的にします。Repo<T>