2016-11-24 19 views
2

データベースからジェネリックタイプに基づいてデータを返すメソッドを作成しようとしています。ネストされたジェネリックタイプのジェネリックメソッドを制限する方法

インターフェース:(この定義はコンパイル)

public interface IOrderPosition<TOrder, TArticle, TOrderPosition> 
    where TOrder : IOrder 
    where TArtile : IArticle 
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition> 
{ 
    long? id { get; set; } 
    TOrder order { get; set; } 
    TArtile article { get; set; } 
    List<TOrderPosition> subPositions { get; set; } 
} 

可能具体的な実施:に基づく一般的な方法を記述しようとする(この定義はコンパイル)

public class OrderPosition : IOrderPosition<Order, Article, OrderPosition> 
{ 
    public long? id { get; set; } 
    public Order order { get; set; } 
    public Article article { get; set; } 
    public List<OrderPosition> subPositions { get; set; } 
} 

インターフェイス:(この定義はコンパイルされません)

public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id) 
    where TOrder : IOrder 
    where TArticle : IArticle 
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition> 
{ 
    .. 
} 

エラー:

'DataSourceOrder.GetOrderPositionOfOrder<TOrderPosition>()' does not define type parameter 'TOrder' 
'DataSourceOrder.GetOrderPositionOfOrder<TOrderPosition>()' does not define type parameter 'TArticle' 
The type or namespace name 'TOrder' could not be found (are you missing a using directive or an assembly reference?) 
The type or namespace name 'TArticle' could not be found (are you missing a using directive or an assembly reference?) 

次のように使用する:

List<OrderPosition> positions = GetOrderPositionOfOrder<OrderPosition>(5); 
List<TransferOrderPosition> transferPositions = GetOrderPositionOfOrder<TransferOrderPosition>(5); 

質問:

なぜインタフェース用にコンパイルされますが、メソッド用にコンパイルされませんか?

私はどちらもうまく動作すると思われますが、どちらも失敗すると思います。コンパイルは、TOrderとTArticleの型を、TOrderPositionに与えられた型から推論することができ、これは記事と順序の両方の具体的な型を定義すると仮定しました。

なぜこのようなことが起こり、すべてのタイプを明示的に指定しなくても問題を解決できるかどうかを知りたいと思います。

+3

しかし、あなたのメソッドにはTOrderとTArticleのジェネリックパラメータを定義しません。それ以外の場合はコンパイルします。そしてクラスのために、3つすべて(TOrder、TArtile、TOrderPosition) – Evk

+0

@Evkを指定すると、これはうまくいきませんでした。私は、コンパイラが何らかの理由で欠落している型を '私はすべての型をリストすることを避けたいので、OrderPosition'(実際には3以上のものがあります) – Holly

答えて

3

これはインターフェイスではコンパイルされますが、メソッドではコンパイルされません。

さて、あなたはGetOrderPositionOfOrder方法でIOrderPositionインタフェースではなく、中TOrderTArticleを宣言しています。

public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id) 
    where TOrder : IOrder 
    where TArticle : IArticle 
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition> 
{ 
    ... 
} 

そして、このようにそれを呼び出す:

var list = GetOrderPositionOfOrder<Order, Article, OrderPosition>(5); 

しかし、あなたのようGetOrderPositionOfOrderをコールする場合:

あなたはメソッド宣言ではこれらの一般的なパラメータを宣言する必要が

var list = GetOrderPositionOfOrder<OrderPosition>(5); 

OrderArticleはゲッターのみのプロパティでなければなりません(ただし、OrderPositionでこれらのプロパティはsetアクセサを持つことができる)という

interface IOrderPosition<out TOrder, out TArticle, TOrderPosition> 
    where TOrder : IOrder 
    where TArticle : IArticle 
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition> 
{ 
    long? id { get; set; } 
    TOrder order { get; } 
    TArticle Article { get; } 
    List<TOrderPosition> subPositions { get; set; } 
} 

注:TOrderTArticleIOrderPosition共変を作ります。

と方法:

public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id) 
    where TOrderPosition : IOrderPosition<IOrder, IArticle, TOrderPosition> 
{ 
    ... 
} 

がこれを行うと、あなたがGetOrderPositionOfOrder<OrderPosition>(5)のような呼び出しを行うことができます。

+0

すべての型を明示的に宣言する必要がない方法を示してくれてありがとう、それは全体の優雅さを取り去ります悲しいことに、おそらくそれは私がそれを必要としているので、おそらく私には役に立たないでしょう.Net 3.5 CF、それらの値を設定する必要もあります。 – Holly

+0

@Holly:Uhmm、そしておそらくIOrderPosition where where TOrderPosition:IOrderPosition '(あなたが望むならば、' id'と 'subPositions'プロパティを持っています)、あなたの現在のインターフェースはこのインターフェースを継承します。次に、次のようなメソッドを宣言できます: 'GetOrderPositionOfOrder (long?id)ここで、TOrderPosition:IOrderPosition ' –

+1

提案をいただきありがとうございます。私は同じことを考えていますが、すべてのタイプを反映してキャストする必要があるため、上に戻ると、ネストされたジェネリック型は推測されません(私が前提としていた)、すべての型パラメータを推測するために、具体的な型のOrderPositionのインスタンスをパラメータとして提供しようとしましたが、今私はちょっとJAVAsが恋しい? extends ClassName' ;-) – Holly

0

インターフェイスでは、それを一般的な3種類のTOrder, TArticle, TOrderPositionを受け入れるように定義するので、これらのタイプを制約することができます。

あなたの方法は、単一の種類、TOrderPositionを定義し、コンパイラは、あなたのメソッド定義で制約where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>から他のタイプを必要とするという事実を推測することはできません。

public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id) 
where TOrder : IOrder 
where TArticle : IArticle 
where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition> 
{ 
.. 
} 
2

エラーを見てみましょう:あなたがする必要がどのような

はあなたのインターフェイスのためにやったのと同じ方法で、あなたの一般的な方法上のすべてのタイプが定義され

「DataSourceOrder .GetOrderPositionOfOrder()TOrder ' 'DataSourceOrder.GetOrderPositionOfOrder(」typeパラメータを定義していない')はTArtile '

' typeパラメータを定義していません'

存在しない型パラメータを参照しています。
あなたが方法でそれらを定義することになっている、あなたがインターフェイスでそれらを定義しているのと同じ方法:

public static List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id) 

メソッドを呼び出すことを意味ちょっと醜いようになります。

var positions = GetOrderPositionOfOrder<Order, Position, OrderPosition>(5); 
var transferPositions = GetOrderPositionOfOrder<TransferOrder, TransferArticle, TransferOrderPosition>(5); 

ときメソッドを呼び出すか、すべての型パラメータを提供するか、または(もし推測できる場合は)noneを指定する必要があります。仕方ないよ。

関連する問題