2017-07-23 65 views
0

我有以下的階層結構如何將IRepository <Invoice>和IRepository <Estimate>作爲IRepository <SalesTransaction>進行抽象?

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<SalesTransaction>抽象IRepository<Invoice>IRepository<Estimate>

IRepository<Invoice> invoiceRepository = /* Create instance */; 
IRepository<SalesTransaction> salesTransaction = invoiceRepository; 

上面的代碼不能編譯。是否有解決方法讓它能夠編譯和工作?

+0

看看https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/ – Nkosi

+1

而這個https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/creating-variant-generic-interfaces – Nkosi

+0

它是否因爲您提到將其轉換爲SalesReceipt而不是編譯,但是繼承自SalesTransaction? – Tony

回答

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中也可用的屬性。

+0

感謝您的回答。說實話,這不是我期待的答案。我無法爲每個存儲庫創建一個包裝,更不用說覆蓋存儲庫中的每個方法。 – burnt1ce