我有返回收集和協方差的問題,我想知道是否有人有更好的解決方案。如何處理在c#中返回集合時的協方差?
的情況是這樣的:
我有2個版本執行,我想保留的版本實現完全獨立的(儘管它們可能具有相同的邏輯)。在實現中,我想返回一個項目列表,因此在界面中,我會返回該項目的界面列表。但是,在界面的實際實現中,我想返回該項目的具體對象。在代碼中,它看起來像這樣。
interface IItem
{
// some properties here
}
interface IResult
{
IList<IItem> Items { get; }
}
然後,將會有2個命名空間具有這些接口的具體實現。例如,
命名空間版本1
class Item : IItem
class Result : IResult
{
public List<Item> Items
{
get { // get the list from somewhere }
}
IList<IItem> IResult.Items
{
get
{
// due to covariance, i have to convert it
return this.Items.ToList<IItem>();
}
}
}
會有下命名空間版本2同樣的事情另一種實現方式。
要創建這些對象,將會有一個工廠根據需要獲取版本並創建適當的具體類型。
如果來電者知道確切的版本並執行以下操作,代碼工作正常
Version1.Result result = new Version1.Result();
result.Items.Add(//something);
不過,我想用戶能夠做這樣的事。
IResult result = // create from factory
result.Items.Add(//something);
但是,因爲它已經轉換成另一個列表,添加什麼都不會做,因爲項目不會被添加回原來的結果對象。
我能想到的幾個解決方案,如:
- 我可以同步兩個名單,但似乎是額外的工作要做
- 返回IEnumerable的,而不是IList中,並添加一個方法創建/刪除收藏
- 創建一個自定義集合了利用TConcrete和TInterface
我明白爲什麼會發生(由於類型安全和所有),但沒有workaroun的我認爲可以看起來很優雅。有人有更好的解決方案或建議嗎?
在此先感謝!
更新
思考這個更後,我想我可以做到以下幾點:
public interface ICustomCollection<TInterface> : ICollection<TInterface>
{
}
public class CustomCollection<TConcrete, TInterface> : ICustomCollection<TInterface> where TConcrete : class, TInterface
{
public void Add(TConcrete item)
{
// do add
}
void ICustomCollection<TInterface>.Add(TInterface item)
{
// validate that item is TConcrete and add to the collection.
// otherwise throw exception indicating that the add is not allowed due to incompatible type
}
// rest of the implementation
}
然後我可以有
interface IResult
{
ICustomCollection<IItem> Items { get; }
}
then for implementation, I will have
class Result : IResult
{
public CustomCollection<Item, IItem> Items { get; }
ICustomCollection<TItem> IResult.Items
{
get { return this.Items; }
}
}
這樣,如果主叫方是訪問Result類,它將通過已經是TConcrete的CustomCollection.Add(TConcrete項)。如果調用者正在通過IResult接口訪問,它將通過customCollection.Add(TInterface項)進行驗證,並確保類型實際上是TConcrete。
我會試一試,看看這是否可行。
我認爲使用選項#2將需要最少量的代碼。它還會減少界面的表面積,因爲實現不會負責完整的IList支持,而調用者可能不需要這些支持。 –
您的解決方案看起來不錯,但您爲什麼直接使用'ICustomCollection'而不是'ICollection '? –
svick
我完全可以。唯一的原因是我有一些專門用於集合的方法,這些方法不適用於需要通過內部代碼訪問的常規ICollection,我忘了提及這些方法。 –
Khronos