工場で汎用インタフェースを使用する場合の型の推測

私の同僚と私は、オンラインストアフロント用の小さなレポートフレームワークをまとめています。我々はリポジトリパターンに従って、リポジトリとして
“reports”を使用し、前記レポートとやりとりするための非常に軽いサービスレイヤーを使用してライブラリを構築しました。私たちのコードはうまく動作し、使い方も簡単です。しかし、個人的に私を気にしていることが1つあります。サービス工場レベルでは、戻り値の型を2回宣言する必要があります(推測されません)。私たちのプロジェクトの基礎は次のとおりです。

レポートインターフェース

これが私たちの “リポジトリ”として使われているものです。ラッパー・クラスやSQL/Oracle
Connection、StorefrontのAPIなどのデータ・アクセス・オブジェクトを取り込みます。

internal interface IReport
{
    T GetReportData(dynamic options);
}

リポジトリファクトリ

これにより、タイプを知ることでレポートを簡単に生成できます。

internal interface IReportFactory
{
    TR GenerateNewReport() where TR : IReport;
}

internal class ReportFactory : IReportFactory
{
    public ReportFactory()
    {
       //some initialization stuff
    }

    public TR GenerateNewReport() where TR : IReport
    {
        try
        {
            return (TR)Activator.CreateInstance(typeof(TR));
        }
        catch(Exception ex)
        {
           //Logging
        }
    }
}

サンプルレポート(リポジトリ)

レポートは次のようになります。それはDataTableを返し、ジェネリックインターフェイスで宣言されていることに注意してください(これはすぐに再生されるようになります)。

internal class ItemReport : IReport
{
    public DataTable GetReportData(dynamic options)
    {
        return new DataTable();
    }
}

レポートサービス

レポート(リポジトリ)を取り込んで動作する軽量サービス。
Lightですが、単体テストなどを簡単に行うことができます。レポートを取得した後に処理を追加したい場合は、簡単に行うことができます。

public interface IReportService
{
    T GetReportData(dynamic options);
}

public class ReportService : IReportService
{
    private readonly IReport _report;

    public ReportService(IReport report)
    {
        _report = report;
    }

    public T GetReportData(dynamic options)
    {
        return _report.GetReportData(options);
    }
}

サービスファクトリ

すべてのサービスファクトリがレポートファクトリを作成する必要があるため、抽象クラスとしてサービスファクトリをセットアップして、デフォルトのコンストラクタを強制します。

public abstract class ReportServiceFactory
{
    protected IReportFactory ReportFactory;

    protected ReportServiceFactory(connection strings and other stuff)
    {
        ReportFactory = new ReportFactory(connection strings and other stuff);
    }
}

次に、機能に基づいて個別のサービスファクトリを作成できます。たとえば、「標準レポート」サービスファクトリと顧客固有のサービスファクトリがあります。実装はここで私の質問です。

public class SpecificUserServiceFactory : ReportServiceFactory
{
    public SpecificUserServiceFactory(connection strings and other stuff) : base(connection strings and other stuff){}

    public IReport GetItemReport()
    {
        return new ReportService(ReportFactory.GenerateNewReport());
    }
}

サービスファクトリを作成するときに、なぜそれほど冗長でなければならないのですか?私は戻り値の型を2回宣言します。なぜ私はこのようなことをすることができません:

return new ReportService(ReportFactory.GenerateNewReport());

私はDataTableを宣言していないことに注意してください。私はItemReportがIReportであるという事実から推論すべきだと思います。このように動作させる方法に関する提案は、大いに感謝しています。

このような長い説明をして申し訳ありませんが、このような簡単な質問をしてもらえますが、その裏づけのコードがすべて解決策になると思いました。もう一度ありがとう!

ベストアンサー

私はコンパイラが ItemReport から DataTable
を推論できるとは思わない。しかし、非ジェネリッククラスの静的ジェネリックメソッドを使用することで
DataTable を2回指定することを避けることができます。

ReportService.Create(reportFactory.GenerateNewReport())
public static class ReportService
{
    public static ReportService Create(IReport report)
    {
        return new ReportService(report);
    }
}

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です