2015-12-29 13 views
6

私はC#でジェネリックスが大好きですが、時にはそれらを使って作業することで少し複雑になることがあります。以下の問題は、私は今、毎回走っています。このシナリオをよりシンプルにする方法はありますか?今、私の質問があるC#でネストされたジェネリックを簡略化することは可能ですか?

public class In : Inner 
{ 
} 

public class Out : Outer<In> 
{ 
} 

public class HandleOut : Handler<Out, In> 
{ 
    public override void SetValue(In value) { } 
} 

public abstract class Inner 
{ 
} 

public abstract class Outer<T> 
    where T : Inner 
{ 
} 

public abstract class Handler<TOuter, TInner> 
    where TOuter : Outer<TInner> 
    where TInner : Inner 
{ 
    public abstract void SetValue(TInner value); 
} 

そして、いくつかの単純な実装:のために私はどのように、私は誰かが3つのベースクラスを考える

:)をすることができます願って見ることができませんのタイプはTInnerで、タイプが「Out」であるため、HandleOutの定義を簡略化してpublic class HandleOut : Handler<Out>のようなものにしても、のパラメータとして内部タイプを使用できるようになります?

これは非常に単純な例ですが、通常はすべての定義を第1の型から論理的に推論できるような定義では、ジェネリック型の長いリストを取得することがあります。私は行方不明のトリックはありますか?

+2

コンパイルするようにコードを修正しました。質問のPOVから正しいかどうか確認してください。 – Enigmativity

+4

あなたが尋ねていると思うものと100%一致しているわけではありませんが、Eric Lippertの[なぜジェネリック制約は継承されないのですか?](http://ericlippert.com/2013/07/15/なぜ、継承されていないという事実は、Enigmativityがあなたのコードを修正して* more * constraintを追加しなければならなかった理由です) –

+0

ありがとう、@エニグマティビティ。私はちょうどその場でコードを書いた - あなたの変更はちょうど私の考えによるものです:) –

答えて

1

そのような推論は、おそらく可能であるべきであるが、それはlangugeの一部ではありません。これをRoslynに提案することに興味があります(新しい問題を開く)。もちろん、このタイプのジェネリック制約の推論は、複雑なケースでは問題になるかもしれませんが、少なくとも単純なケースでは実行可能です...それでもC#チームは自分の時間と労力をかけなければいけませんか?

Why are generic constraints not inheritedDamien_The_Unbelievershared on the commentsが点在しています。 OutはすでにあなたのタイプInTOuterが必要とされていない一般的なパラメータを与えることは事実である一方、


とにかく、コードの中であなたの提示。

次のコードは、同様に動作:あなたがそれを必要とする場合

public abstract class Inner 
{ 
} 

public abstract class Outer<T> 
    where T : Inner 
{ 
} 

public abstract class Handler<TInner> // NOTE: TOuter removed 
    where TInner : Inner 
{ 
    public abstract void SetValue(TInner value); 
} 

public class In : Inner 
{ 
} 

public class Out : Outer<In> 
{ 
} 

public class HandleOut : Handler<In> // NOTE: Out removed 
{ 
    public override void SetValue(In value) { } 
} 

ので、代わりにTOuterのOuter<TInner>を使用して検討することができます。もちろん、TOuterのリストを保持している場合は、派生タイプTOuterではなく、派生タイプOuter<TInner>が許可されるため、制限が少なくなります。

ジェネリック制約に「新規」を指定していないため、このタイプのオブジェクトは作成されませんが、ケースが到着した場合はコンストラクタにFunc<Outer<TInner>>を受け入れることができます。

+0

あなたの返信ありがとうございます。私の例では、私はTOuterを失うことができる正しいですが、それは本当の人生の例を与えないことによるものです - 私は実際のケースでは、TOuterが必要になります。これがC#が時間を費やす必要があるものなのかどうかは分かりません。それは、私がこの種の問題に遭遇することの多い私のスタイルのコーディングであるかもしれませんが、私はそれを非常に便利で、非常に良い抽象化があると感じるでしょう。おそらく、次のようなものです:public abstract class Handler where ...? –

+0

@ChrisRidge構文はうまくいくかもしれませんが、その一般的なパラメータが暗黙的であってもいなくても、システムが現在行われている方法はほとんどありません。だから私はそれを派生型の推論と見なしています。いくつの一般的なパラメータがありますか? [4以上のケースは考えられないかもしれません]あなたが開発しているものの特典かもしれないし、抽象化が不足しているかもしれません...しかし、それがいくつかの特定のケースを緩和するならば、オプションであると考えてください。実際には必要ありませんが、相互運用とコードのメンテナンスが容易になります。 – Theraot

+0

私の現在のプロジェクトでは自分自身が4つ以上は持っていませんが、これは何度も実装されているインターフェイスにあります。実装ごとに4つのタイプすべてを指定することは面倒であり、コードを理解しにくくします。これは必須の機能ではありませんが、私たちにとっては素晴らしい機能です:) –

関連する問題