2017-08-07 67 views
1

我有以下的實施產生一個編譯器錯誤通用工廠方法創建泛型類型來龍去脈

「無法隱式轉換類型‘ParentMenuItemFilter’到 ‘IMenuItemFilter<MenuItem>’。一個顯式轉換存在(是你 缺少強制轉換?)

public class MenuItem 
{ 
    // implementation removed for clarity 
} 

public class ParentMenuItem : MenuItem 
{ 
    // implementation removed for clarity 
} 

public interface IMenuItemFilter<TMenuItemType> 
     where TMenuItemType : MenuItem 
{ 
    TMenuItemType ApplySecurity(TMenuItemType menuItem); 
} 


public class ParentMenuItemFilter : IMenuItemFilter<ParentMenuItem> 
{ 
    public ParentMenuItem ApplySecurity(ParentMenuItem menuItem) 
    { 
     // implementation removed for clarity 
    } 
} 

public class MenuItemFilterFactory 
{ 
    public IMenuItemFilter<MenuItem> Create<TMenuItemType>(TMenuItemType menuItem) 
      where TMenuItemType : MenuItem 
    { 
     if (typeof(TMenuItemType) == typeof(ParentMenuItem)) 
     { 
      // here is the errored line!... 
      return new ParentMenuItemFilter(this); 
     } 
     else if (/* create some other types*/) 
     { 
      ... 
     } 
    } 
} 

所以我的兩個最好的朋友,協方差和逆變進來玩。我想實現上述,如果它是可能是通過通用工廠方法,它將返回IMenuItemFilter的相應實例,該實例將根據menuItem參數對Create方法起作用。

我想將MenuItem實例傳遞給工廠方法以解決此問題。

我試過在界面和其他定義中有一個進出in TMenuItemTypeIn, out TMenuItemTypeOut - 無濟於事。我曾在Stack Exchange的CodeReview上發佈過50/50,但認爲這同樣是一個編碼問題和代碼設計問題。今天我花了很大一部分時間試圖讓這個工作,但有很多中斷。

+0

我想你需要的只是'公共接口IMenuItemFilter '。但是,如果你檢查實際的類型,這是非常不通用的,不是嗎?我懷疑你的方案需要泛型,或者至少不適合你的工廠。 – HimBromBeere

+0

因爲IMenuItemFilter指定了與in和out參數相同的TMenuItemType,所以我不能這樣做嗎?在這個編譯器barfs! – Andez

+0

是否有你沒有從你的工廠方法返回'IMenuItemFilter '的原因? –

回答

2

如果這不是一個過於簡單化的例子,那麼每個類型都應該有一個方法。 CreateParentMenuItemFilter或類似的東西。你的通用方法似乎只會使事情複雜化,沒有任何好處。

+0

事實上,裂縫正在出現。我正在尋找一個優雅的方法 - 只是重新思考整體問題的代碼策略。 – Andez

1

我想你所需要的只是public interface IMenuItemFilter<out TMenuItemType>。然而,基於泛型類型參數完成不同事情的泛型方法有點奇怪,而不是泛型的意圖 - 這就是爲什麼它們被稱爲泛型:它們對不同的類執行相同的操作。

所以我建議去非通用在你的工廠:

public class MenuItemFilterFactory 
{ 
    public IMenuItemFilter Create(MenuItem menuItem) 
    { 
     if (menuItem.GetType() == typeof(ParentMenuItem)) 
     { 
      return new ParentMenuItemFilter(this); 
     } 
     else if (/* create some other types*/) 
     { 
      ... 
     } 
    } 
} 

但是這裏假設你有你的界面的非通用版本,以及從通用的一個派生:

public interface IMenuItemFilter 
{ 
} 
public interface IMenuItemFilter<TMenuItemType> : IMenuItemFilter 
     where TMenuItemType : MenuItem 
{ 
    TMenuItemType ApplySecurity(TMenuItemType menuItem); 
} 
+0

但是,如果我從工廠返回'IMenuItemFilter',我無法訪問位於'IMenuItemFilter '上的'ApplySecurity'方法' – Andez