制約

2013-05-10 11 views
8

と部分的にジェネリック型推論の欠如を中心に作業を私はこのメンバーを持っている(リポジトリで使用されている)のインターフェイスを持つ:制約

T FindById<T, TId>(TId id) 
    where T : class, IEntity<TId> 
    where TId : IEquatable<TId>; 

これは、呼び出し側がエンティティタイプ(T)を指定することができますし、そのタイプはIdフィールド(TId)です。このインターフェイスの実装者は、タイプTのエンティティを見つけ、idパラメータを使用して、そのID(IEntity<TId>で定義されている)に従ってフィルタリングします。

現在、私はこのようにそれを呼んでいる:

int id = 123; 
var myApproval = PartsDC.FindById<Approval, int>(id); 

理想的には私がこれを行うにはしたいと思います:

int id = 123; 
var myApproval = PartsDC.FindById<Approval>(id); 

私はこの質問に対しての答えを読んだ:

Partial generic type inference possible in C#?

私が望む構文を得ることはできませんが、近づけることができます。私はかなり私の場合は、私の一般的なパラメータの制約のためにセットアップを取得することはできません。

ここで私がこれまで持っているものです。

public class FindIdWrapper<T> where T : class 
{ 
    public readonly IDataContext InvokeOn; 

    public FindIdWrapper(IDataContext invokeOn) 
    { 
     InvokeOn = invokeOn; 
    } 

    T ById<TId>(TId id) where TId : IEquatable<TId> 
    { 
     return InvokeOn.FindById<T, TId>(id); 
    } 
} 

public static class DataContextExtensions 
{ 
    public static FindIdWrapper<T> Find<T>(this IDataContext dataContext) where T : class, IEntity 
    { 
     return new FindIdWrapper<T>(dataContext); 
    } 
} 

私が手にコンパイルエラーがある:

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'PartsLegislation.Repository.IDataContext.FindById<T,TId>(TId)'. There is no implicit reference conversion from 'T' to 'PartsLegislation.Repository.IEntity<TId>'.

私は私のラッパークラスでTのみに制限されているので、それは言っているかを理解参照型ですが、FindById関数はIEntity<TId>であることを望んでいますが、TIdがメソッド内にあるので、それを行うことはできません(そうでなければ、正方形 1)。

どうすればこの問題を回避できますか(できません)?

+0

'FindIdWrapper'に制約として' TID'を追加できませんか? – Nick

+0

@Nickいいえ、部分アプリケーションの時点で 'TID'が分からないので –

答えて

4

実際にはTIdという制約をコンパイラに納得させることができないため、通常の方法では動作しません。ただし、順序を逆にすることができます。つまり、

var obj = ById(id).Find<SomeType>(); 

エレガントではありませんが、動作します。実装:

public Finder<TId> ById<TId>(TId id) where TId : IEquatable<TId> 
{ 
    return new Finder<TId>(this, id); 
} 
public struct Finder<TId> where TId : IEquatable<TId> 
{ 
    private readonly YourParent parent; 
    private readonly TId id; 
    internal Finder(YourParent parent, TId id) 
    { 
     this.id = id; 
     this.parent = parent; 
    } 
    public T Find<T>() where T : class, IEntity<TId> 
    { 
     return parent.FindById<T, TId>(id); 
    } 
} 

注意:両方のパラメータタイプを明示的に指定するほうが簡単かもしれません。

+0

私は私の答えで同じことを書いていました。マークはあなたが速すぎます!私はコード内で同じアプローチを使用していますが、私はあまりにもエレガントなものを書くことができれば幸いです。 –

+0

すばらしい、ありがとう!正直言って、部分的なジェネリック型の推論を行うことができないことに気がついたのは、ほとんどが学術的だった。 :) –

+0

私はそれを "より良く"するために少し異なる名前を持っています: 'Lookup(id).From ()'。 –