如何将IRepository <invoice>和IRepository <estimate>抽象为IRepository <salestransaction>?

时间:2017-07-23 16:28:56

标签: c# generics

我有以下类结构

public abstract class SalesTransaction
{

}

public class Invoice : SalesTransaction
{

}

public class Estimate : SalesTransaction
{

}

public interface IRepostory<T>
{
    T First(Expression<Func<T, bool>> predicate);
    void Add(T item);
    T Single(Expression<Func<T, bool>> predicate, bool disableTracking = false);
}

我可以通过将其IRepository<Invoice>投射到IRepository<Estimate>而以某种方式抽象IRepository<SalesTransaction>IRepository<Invoice> invoiceRepository = /* Create instance */; IRepository<SalesTransaction> salesTransaction = invoiceRepository; 吗?

<?php
 if (is_dir('dir')) {
if ($dh = opendir('dir')) {
    while (($file = readdir($dh)) !== false) {
        echo "filename:".$file."<br />";
    }
}
}?>

上面的代码无法编译。是否有一种解决方法可以让它编译和工作?

1 个答案:

答案 0 :(得分:0)

您可以创建一个SalesTransaction存储库作为更具体类型的存储库的包装。 (此处显示发票)

public class InvoiceAsSalesTransactionRepository : IRepostory<SalesTransaction>
{
    private readonly IRepostory<Invoice> _invoiceRepository = new InvoiceRepository();

    public void Add(SalesTransaction item)
    {
        if (item is Invoice invoice) {
            _invoiceRepository.Add(invoice);
        } else {
            throw new ArgumentException("Item must be Invoice");
        }
    }

    public SalesTransaction First(Expression<Func<SalesTransaction, bool>> predicate)
    {
        return _invoiceRepository.First(ToInvoicePredicate(predicate));
    }

    public SalesTransaction Single(Expression<Func<SalesTransaction, bool>> predicate,
                                   bool disableTracking = false)
    {
        return _invoiceRepository.Single(ToInvoicePredicate(predicate), disableTracking);
    }

    private static Expression<Func<Invoice, bool>> ToInvoicePredicate(
        Expression<Func<SalesTransaction, bool>> predicate)
    {
        var param = Expression.Parameter(typeof(Invoice), predicate.Parameters[0].Name);
        return Expression.Lambda<Func<Invoice, bool>>(predicate.Body, param);
    }
}

如您所见,您需要一些反射魔法来转换谓词类型。因此,您不能简单地投射您的存储库。请注意,我们不需要在此处投射任何内容,因为有效的SalesTansaction谓词始终是有效的Invoice谓词,因为SalesTansaction仅包含Invoices中也可用的属性。