2016-06-27 9 views
6

使用object` `返すために親の型としてキャストが、許可します設定例:は、派生型が派生型の(私はコンパイルされません知っていると正しくない)次のコードを考える方法

var myFetchers = new List<Fetcher> { 
    new Fetcher<string>(() => new List<string> { "white", "black" })), 
    new Fetcher<int>(() => new List<int> { 1, 2 })) 
}; 

これを行うにはどうすればよいでしょうか?

IEnumerable<IEnumerable<object>> fetcherResults = 
    myFetchers.Select(fetcher => fetcher.Fetch()); // get objects from derived method 

TLDR。私はこれについてもう少し考えました。私の質問を述べる別の方法は、​​リスト内のすべてのアイテムに対してFetchメソッドを実行し、各アイテムの基本タイプを特定することなく、そのタイプのキャストを行うことなく、 Fetchメソッド自体からIEnumerable<object>を返さないでください。

ここで重要なのは、異なるジェネリックタイプのオブジェクトが親タイプのコレクションにあるとき、派生したタイプのメソッドを実行したいが結果はで、IEnumerable<T>ではなく返すようにしたい。 (これは必要ならば別の方法を使って行うことができますが、同じ名前であればいいと思いますが)これは、フェッチャについて知る必要のないコードの部分がそのデータを持つことができるようにするためです(そしてちょうどfetcherResultsを渡す)が、フェッチャーを気にするコードの部分は、フェッチャーがどのタイプのデータを扱うかを完全に無視することができます(懸念事項ではなく、データの消費者のみがその特定のタイプで動作する必要があります)。

私はここで継承を使用する必要はなく、インターフェイスIFetcherも同様に機能します。私は、明示的なインターフェイスの実装が役立つかもしれない方法を考え続けて、私はちょうど私のためにこの作品の作り方を今すぐループを閉じていないよ。いつものように

// in a class implementing ICollection<T> 
public IEnumerator<T> GetEnumerator() => _collection.GetEnumerator(); 
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable) _collection).GetEnumerator(); 

を、実際の状況は、このような(これよりも複雑ですフェッチャがデータベースから提供しているデータなど)。しかし、この1つの部分をダウンさせることは、私が必要とするものすべてになります。

私は以下のリソースを無駄に見ています:implement an inheritable method that returns an objectcall method on generic type from abstract parent。私が正しく質問を理解していれば

+0

'FetchGeneric()。キャスト()'を単に呼び出す 'IEnumerable FetchGeneric()'と 'IEnumerable Fetch()'はありませんか? –

+0

私はそれらを同じ名前にしたいと思って捨てられたと思う。今あなたが言及していることははっきりしているようです。しかし、後で派生型を使用するときにフェッチを延期することにした場合、同じメソッド名を使用して特定の型を取得できることは間違いありません。 – ErikE

+0

質問を更新しました。TLDRを開始する新しい段落を参照してください。 – ErikE

答えて

3

疑わしい明示的な実装でこれを行うための単純な方法があります。これは、抽象クラスではなくインターフェイスを使用する場合にのみ使用できます。この実装では

public interface IFetcher { 
    IEnumerable<object> Fetch(); 
} 

public class Fetcher<T> : IFetcher { 
    private readonly Func<IEnumerable<T>> _fetcher; 
    public Fetcher(Func<IEnumerable<T>> fetcher) { _fetcher = fetcher; } 
    IEnumerable<object> IFetcher.Fetch() => Fetch().Cast<object>(); 
    public IEnumerable<T> Fetch() => _fetcher(); 
} 

クラスアクセスバージョンは、より特定IEnumerable<T>を返しながら、コールのインタフェースバージョンは、IEnumerable<object>を返します。インターフェースを通してフェッチャーを呼び出すと、最初に解決されます。クラスを呼び出すと、2番目のクラスに解決されます。

+0

はい!これは私が探していたものです。なぜ私はそれを見ることができませんでしたか?ありがとうございました! – ErikE

2

、あなたはFetcher<T>をすることによって、問題を解決することができ、このような一般的なインタフェースIFetcher<T>を実装しています。その後、

public interface IFetcher<T> 
{ 
    IEnumerable<T> Fetch(); 
} 

public class Fetcher<T> : IFetcher<T> 
{ 
    private readonly Func<IEnumerable<T>> _fetcher; 
    public Fetcher(Func<IEnumerable<T>> fetcher) { _fetcher = fetcher; } 
    public IEnumerable<T> Fetch() => _fetcher(); 
} 

そして、このようなIFetcher<TTo>IFetcher<TFrom>を変換することができ、アダプタを作成します:

public class Adaptor<TFrom, TTo> : IFetcher<TTo> 
{ 
    private readonly IFetcher<TFrom> _fetcher; 

    public Adaptor(IFetcher<TFrom> fetcher) 
    { 
     _fetcher = fetcher; 
    } 

    public IEnumerable<TTo> Fetch() 
    { 
     return _fetcher.Fetch().Cast<TTo>(); 
    } 
} 

これはIFetcher<string>からIFetcher<object>に変換する例を可能にします。あなたは簡単にこのような何かを行うことができ

public static class ExtensionMethods 
{ 
    public static Converter<TFrom> Convert<TFrom>(this IFetcher<TFrom> fetcher) 
    { 
     return new Converter<TFrom>(fetcher); 
    } 

    public class Converter<TFrom> 
    { 
     private readonly IFetcher<TFrom> _fetcher; 

     public Converter(IFetcher<TFrom> fetcher) 
     { 
      _fetcher = fetcher; 
     } 

     public IFetcher<TTo> To<TTo>() 
     { 
      return new Adaptor<TFrom, TTo>(_fetcher); 
     } 
    } 
} 

:この拡張メソッドの助けを借りて

static void Main(string[] args) 
{ 
    var myFetchers = new List<IFetcher<object>> 
    { 
     new Fetcher<string>(() => new List<string> { "white", "black" }).Convert().To<object>(), 
     new Fetcher<int>(() => new List<int> { 1, 2 }).Convert().To<object>() 
    }; 

    var results = myFetchers.Select(x => x.Fetch()); 
} 

あなたが拡張メソッドなしで行うことができますが、それはあなたを行いますしてくださいコードをより読みやすくする。

+0

私はそれを手に入れます。別のインダイレクションで後でFetcherをラップして、元のFetcherを取得してから、オブジェクトを返すインタフェースを実装するということです。後でFetchするときに正しいメソッドを実行しますが、必要なオブジェクト型に変換します。コンパイラに型を推測させ、その知識をラッパーに格納させます。私はこれについて考える必要がありますが、それは確かに便利ですが、私が降りたいルートかどうかは分かりません。 – ErikE

関連する問題