2010-09-23 22 views
4

我試圖做這樣的事情:實現多個通用接口 - 錯誤類型

public interface IRepository<T> 
{ 
    T Get<T>(int id); 
} 

public interface IFooBarRepository : IRepository<Foo>, IRepository<Bar> 
{ 
} 

IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); 
Foo foo = repo.Get<Foo>(1); 

我得到一個警告:

類型參數「T」具有相同的名稱作爲類型從外類型 'IRepository'

和誤差參數:

呼叫是下列方法或屬性之間曖昧: 'IRepository.Get(INT)' 和 'IRepository.Get(INT)'

有關如何使此模式有效的任何想法?

回答

7

調用相應的一個,你需要在適當的方式編譯思表達:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); 
IRepository<Foo> fooRepo = repo; 
Foo foo = fooRepo.Get(1); 

請注意,您可以只是丟在一個聲明:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); 
Foo foo = ((IRepository<Foo>)repo).Get(1); 

...但這看起來很醜陋。

那處理調用的方法。 實現一個類中的兩個接口都是下一個障礙......因爲它們在參數方面具有相同的簽名。你必須執行其中至少有一個明確的 - 如果你沒有這樣可能會導致混亂少兩個:

public class FooBarRepository : IFooBarRepository 
{ 
    Foo IRepository<Foo>.Get(int id) 
    { 
     return new Foo(); 
    } 

    Bar IRepository<Bar>.Get(int id) 
    { 
     return new Bar(); 
    } 
} 

編輯:您還需要做出Get非泛型方法:目前你」重新嘗試重新聲明IRepository<T>.Get<T>中的類型參數T;您只想使用現有的型號IRepository<T>

+0

阿哈...這個工程。雖然我不明白爲什麼它不能像我最初寫的那樣工作......啓發我們,哦,Skeety一個! :) – Jonas 2010-09-23 20:12:12

+0

好的,但顯式實現呢? – 2010-09-23 20:13:27

+0

@Jonas:你不是試圖調用一個實際的泛型方法(即引入一個新的類型參數),所以你不能指定一個類型參數。相反,您試圖使用表達式作爲特定泛型類型的實現......並且*這是* cast/extra變量的作用。 (編輯:事實上,你已經聲明瞭Get方法,它*是*通用的 - 但它不應該是這樣的。) – 2010-09-23 20:13:32

1

您不需要再次在方法聲明中重複T。它在接口上已經宣佈:

public interface IRepository<T> 
{ 
    T Get(int id); 
} 

還要注意,你需要explicitly implementIFooBarRepository接口,因爲只有Get方法的返回類型不同,這是不可能的。

+0

這照顧我的警告,但後來當我這樣做: Foo foo = repos.Get(1); 我仍然收到「呼叫不明確」的錯誤。 – Jonas 2010-09-23 20:09:58

+0

你需要明確的實現接口。 – 2010-09-23 20:12:37

0

使用顯式實現。要指定哪個Get,首先投射到適當的界面。

1

相反的:

Foo foo = repo.Get<Foo>(1); 

使用

Foo foo = ((IRepository<Foo>)repo).Get(1); 

哪一種違背了使用泛型避免鑄造的整體感覺,但不幸的是你在做什麼也不是沒有可能提供更多提示給編譯器。

2

不幸的是,你不能。這不是泛型如何設計用C#工作的。如果這種模式走,你會總是被迫到想要鑄造repo調用Get()上disambiguiate其接口版本:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); 
Foo foo = ((IRepository<Foo>)repo).Get(1); 

這可能不是你想要的。

您當然可以在IFooBarRepository的實現中實現代理方法,以返回正確的類型......但是,這可能不是您要查找的內容。

你可以,但是,在IFooBarRepository改善正是如此語法創建屬性:

interface IFooBarRepository : IRepository<Foo>, IRepository<Bar> 
{ 
    IRepository<Foo> FooGetter { get; } 
    IRepository<Bar> BarGetter { get; } 
} 

現在你可以這樣寫:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); 
Foo foo = repo.FooGetter.Get(1); 
Bar bar = repo.BarGetter.Get(2); 

在一般情況下,這是需要避免的通用方法是不要」 t接受作爲類型參數類型的形式參數參數。在你的情況下,你試圖將存儲庫的語義直接編碼到類型系統中。將這個權限劃分爲表示存儲庫行爲的類型和表示獲取對象行爲的單獨類型可能會更好。