簡體   English   中英

C#轉換列表 <ObjBase> 作為清單 <Obj>

[英]C# Casting a List<ObjBase> as List<Obj>

為什么我不能將List<ObjBase>List<Obj> 為什么以下不起作用:

internal class ObjBase
   {
   }

internal class Obj : ObjBase
   {
   }   

internal class ObjManager
{
    internal List<Obj> returnStuff()
    {
       return getSomeStuff() as List<Obj>;
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }

}

相反,我必須這樣做:

internal class ObjBase
   {
   }

internal class Obj : ObjBase
   {
   }

internal class ObjManager
{
    internal List<Obj> returnStuff()
    {
       List<ObjBase> returnedList = getSomeStuff();
       List<Obj> listToReturn = new List<Obj>(returnedList.Count);
       foreach (ObjBase currentBaseObject in returnedList)
       {
          listToReturn.Add(currentBaseObject as Obj);
       }
       return listToReturn;
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }
}

我在Visual Studio 2008中收到以下錯誤(為了便於閱讀而縮短):

無法通過引用轉換,裝箱轉換,取消裝箱轉換,換行轉換或空類型轉換將類型“列表”轉換為“列表”

謝謝。

您可以使用System.Linq中的CastToList擴展方法將其放在一行中。

代替

internal List<Obj> returnStuff()
{
   return getSomeStuff() as List<Obj>;
}

做這個:

internal List<Obj> returnStuff()
{
   return getSomeStuff().Cast<Obj>().ToList();
}

我只能從Java視圖中描述“問題”,但是我知道這個方面在C#和Java中都是相同的:

List<ObjBase>不是List<Obj> ,因為它可能包含一個不是Obj對象的ObjBase對象。

List<Obj>的另一種方法不能轉換為List<ObjBase>因為前者保證接受帶有ObjBase參數的Add()調用,后者不接受!

總結一下:即使Obj是一個ObjBaseList<Obj> 也不List<ObjBase>

我認為你誤解了你想要做的演員。 您正在考慮更改列表中存儲的對象的類型,您實際上正在嘗試更改列表本身的類型。 更有意義的是,您無法更改列表本身,因為您已經填充了它。

您可以將其視為基類列表,然后在處理列表項時將其強制轉換,這將是我的方法。

這次嘗試演員的目的是什么?

C#目前不支持泛型類型的方差。 根據我的閱讀,這將在4.0中改變。

有關泛型差異的更多信息,請參見此處

list.ConvertAll看起來很誘人,但有一個很大的缺點:它將創建一個全新的列表。 這將影響性能和內存使用,尤其是對於大型列表。

通過更多努力,您可以創建一個包裝列表類,將原始列表保留為內部引用,並僅在使用它們時轉換項目。

用法:

var x = new List<ObjBase>();
var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>

要添加到庫中的代碼:

public static class Extensions
{
    public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
    {
        return new CastedList<TTo, TFrom>(list);
    }
}

public class CastedList<TTo, TFrom> : IList<TTo>
{
    public IList<TFrom> BaseList;

    public CastedList(IList<TFrom> baseList)
    {
        BaseList = baseList;
    }

    // IEnumerable
    IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }

    // IEnumerable<>
    public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }

    // ICollection
    public int Count { get { return BaseList.Count; } }
    public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
    public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
    public void Clear() { BaseList.Clear(); }
    public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
    public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
    public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }

    // IList
    public TTo this[int index]
    {
        get { return (TTo)(object)BaseList[index]; }
        set { BaseList[index] = (TFrom)(object)value; }
    }

    public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
    public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
    public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}

public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
    public IEnumerator<TFrom> BaseEnumerator;

    public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
    {
        BaseEnumerator = baseEnumerator;
    }

    // IDisposable
    public void Dispose() { BaseEnumerator.Dispose(); }

    // IEnumerator
    object IEnumerator.Current { get { return BaseEnumerator.Current; } }
    public bool MoveNext() { return BaseEnumerator.MoveNext(); }
    public void Reset() { BaseEnumerator.Reset(); }

    // IEnumerator<>
    public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}

Linq有一個ConvertAll方法。 所以像

list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));

我不確定還有什么建議。 我假設ObjBase是基類,如果所有ObjBase對象都是Obj對象,我不確定為什么你會首先擁有這兩個對象。 也許我不合時宜。

編輯:list.Cast方法比上面的方法更好,假設它們可以相互轉換。 在我閱讀其他答案之前忘了這一點。

這是C#的主要痛苦 - 這就是仿制葯的設計方式。 List不擴展List,它只是一個完全不同的類型。 您無法以任何方式將它們轉換或分配給對方,您唯一的選擇是將一個列表復制到另一個列表。

拉撒路
我認為編譯器會意識到我希望對列表的對象進行操作,而不是我試圖自己編譯列表。

更多信息:

public abstract class ObjBase
   {
   }

internal interface IDatabaseObject
   {
   }

public class Obj : ObjBase, IDatabaseObject
   {
   }


internal interface IDatabaseObjectManager
   {
      List<ObjBase> getSomeStuff();
   }

public class ObjManager : IObjManager
{
    public List<Obj> returnStuff()
    {
       return getSomeStuff().Cast <Customer>().ToList<Customer>();
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }
}

現在這個DLL之外的客戶端代碼可以去:ObjManager objM = new ObjManager(); 列表listOB = objM.returnStuff(); 我將為應用程序的這個部分(O / RM)創建幾個ObjObjManager類型。

(Darn評論塊用完了字符!:-)

以下是我如何修復轉換

list<SomeOtherObject>

到了

object

然后到了

List<object>

https://stackoverflow.com/a/16147909/2307326

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM