2013-12-12 68 views
5

所以,這是一個很遲鈍的問題,但讓我看看我是否可以相對簡單地佈置它。可以說我有以下接口:使用具體類型實現ICollection <ISomething>以滿足實體框架

public interface IFoo 
{ 
    ICollection<IBar> Bars { get; set; } 
} 

然後我與落實:

public class Foo : IFoo 
{ 
    public virtual ICollection<IBar> Bars { get; set; } 
} 

只有實體框架不能與接口的工作,所以它幾乎完全忽略了這個導航屬性。爲了獲得EF承認它,我需要將其更改爲:

public virtual ICollection<Bar> Bars { get; set; } 

Bar將是我實現IBar。只是,這沒有實現接口,它要IBar而不是Bar

現在,考慮一個稍微不同的情景,在那裏我剛剛拿到了一個基本的外鍵:

public interface IFoo 
{ 
    IBar Bar { get; set; } 
} 

public class Foo : IFoo 
{ 
    public virtual IBar Bar { get; set; } 
} 

同樣的問題,但在這裏,我可以通過添加解決它:

public class Foo : IFoo 
{ 
    public virtual Bar Bar { get; set; } 
    IBar IFoo.Bar 
    { 
     get { return Bar; } 
     set { Bar = (Bar)value; } 
    } 
} 

EF很高興,因爲它有一個具體的類型,並且界面很開心,因爲它具有IBar的實現。問題在於我無法弄清楚如何將應用於相同的邏輯,因爲(ICollection<Bar>)value引發了一個異常,說「無法將類型ICollection<Bar>隱式轉換爲ICollection<IBar>」。

我該如何正確地演員陣容?

UPDATE

所以,我並沒有給予足夠的重視正在產生錯誤的位置。它實際上是在抱怨get { return Bars; }位。我可以通過它改變擺脫錯誤的:

public class Foo : IFoo 
{ 
    public virtual ICollection<Bar> Bars { get; set; } 
    ICollection<IBar> IFoo.Bars 
    { 
     get { return (ICollection<IBar>)Enumeration.Cast<IBar>(Bars); } 
     set { Bars = (ICollection<Bar>)value; } 
    } 
} 

這似乎有點做作我雖然喜歡我只是掩蓋錯誤,併爲自己創建一個小的定時炸彈。我會很感激任何想法或替代解決方案。

+0

我很好奇:什麼是你的情況下,可能需要這樣做? – IronMan84

+0

我有一個實體實現一個接口,只引用其他接口,而不是具體的類型。 –

+0

你的吸氣和吸氣器是否真的有效?我期望至少有一些有效的集合實例會拋出一個InvalidCastException異常。 – hvd

回答

2

爲了讓協方差/逆變工作中,我定義的導航屬性可枚舉在我的接口:

public interface IFoo 
{ 
    IEnumerable<IBar> Bars { get; } 
} 

public class Foo : IFoo 
{ 
    public virtual ICollection<Bar> Bars { get; set; } 
    IEnumerable<IBar> IFoo.Bars 
    { 
     return this.Bars; 
    } 
} 

這仍然是不夠建在接口類型EF LINQ查詢。

+0

那是有道理的。但是二傳手怎麼樣?你是否預見到我的'set {Bars =(ICollection )值有問題; }'。它是好的還是有更好的方法? –

+0

我不確定二傳手,我不需要它。我的dbcontexts是用具體類語言表達的,而存儲庫是圍繞接口構建的。存儲庫允許用接口語言來聲明LINQ表達式(並且getter對此已足夠),而在存儲庫級別(對具體類型/屬性進行操作)中實現插入。 –

+0

當'value'強制轉換失敗時,我會使用動態轉換檢查和異常編寫setter。 –

0

我使用這樣

public class InterfaceCollectionAdapter<TConcrete, TInterface> : ICollection<TInterface> where TConcrete : TInterface 
{ 
    private Func<ICollection<TConcrete>> _gettor; 
    private Action<ICollection<TConcrete>> _settor; 
    private Func<ICollection<TConcrete>> _factory; 

    private ICollection<TConcrete> Wrapped 
    { 
     get 
     { 
      var value = _gettor(); 

      if (value == null && _settor != null) 
      { 
       value = (_factory != null) 
        ? _factory() 
        : new List<TConcrete>(); 

       _settor(value); 
      } 

      return value; 
     } 
    } 

    public InterfaceCollectionAdapter(Func<ICollection<TConcrete>> gettor, Action<ICollection<TConcrete>> settor = null, Func<ICollection<TConcrete>> factory = null) 
    { 
     _gettor = gettor; 
     _settor = settor; 
     _factory = factory; 
    } 

    public void Add(TInterface item) 
    { 
     Wrapped.Add((TConcrete)item); 
    } 

    public void Clear() 
    { 
     Wrapped.Clear(); 
    } 

    public bool Contains(TInterface item) 
    { 
     return Wrapped.Contains((TConcrete)item); 
    } 

    public void CopyTo(TInterface[] array, int arrayIndex) 
    { 
     var wrapped = Wrapped; 
     foreach (var item in wrapped) 
     { 
      array[arrayIndex++] = (TInterface)item; 
     } 
    } 

    public int Count 
    { 
     get { return Wrapped.Count; } 
    } 

    public bool IsReadOnly 
    { 
     get { return Wrapped.IsReadOnly; } 
    } 

    public bool Remove(TInterface item) 
    { 
     return Wrapped.Remove((TConcrete)item); 
    } 

    public IEnumerator<TInterface> GetEnumerator() 
    { 
     var wrapped = Wrapped; 
     foreach (var item in wrapped) 
      yield return item; 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 

一個通用的接口適配器然後在POCO你只需做到這一點

public Foo() 
{ 
    public Foo() 
    { 
     _bars = new InterfaceCollectionAdapter<Bar, IBar>(() => this.Bars, (value) => { this.Bars = value; }); 
    } 

    private InterfaceCollectionAdapter<Bar, IBar> _bars; 

    [NotMapped] 
    ICollection<IBar> IFoo.Bars 
    { 
     get 
     { 
      return _bars; 
     } 
    } 
+0

我有一個甚至是「更智能」的版本,可以自動地報出底層EF所需的虛擬內容,因此您的構造函數中沒有新的列表()調用。答案已更新。查看簡單版本的編輯歷史記錄。 – IDisposable

相關問題