C# - 可以列出吗?无缝转换为列表或类似的?

发布于 2024-08-13 11:00:21 字数 1774 浏览 4 评论 0原文

我的控件中有一个 DataSource ,它始终是一个 List ,其中 T 必须从 IEntity 继承。

public class MyClass<T> where T : IEntity
{
    public List<T> DataSource
    {
        get;
        set;
    }
}

现在,显然您不能将 List 转换为 List 执行以下操作:

List<IEntity> wontWork = (List<IEntity>)this.DataSource;

How can I get the DataSource as a List of IEntity,同时仍然能够从 DataSource 添加和删除项目?即我可以执行以下操作,但从它返回的列表中删除不会从数据源中删除:

public List<TOut> GetDataSourceCopyAsUnderlyingType<TOut>()
{

    if (this.DataSource == null)
    {
        return new List<TOut>();
    }
    else
    {

        // Get the list and the enumerator
        IList list = (IList)this.DataSource;
        IEnumerator enumerator = list.GetEnumerator();

        // Build the target list
        List<TOut> targetList = new List<TOut>();

        int i = 0;
        while (enumerator.MoveNext())
        {
            TOut entity = (TOut)list[i];
            targetList.Add(entity);
            i++;
        }

        return targetList;

        }

    }

基本上,我需要某种方法来执行以下操作:

List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>();
int dataSourceCount = this.DataSource.Count;   // Equals 5
int interfaceCount = interfaceList.Count;      // Equals 5

interfaceList.RemoveAt(0);
int dataSourceCount = this.DataSource.Count;   // Equals 4
int interfaceCount = interfaceList.Count;      // Equals 4

只是补充一下,我不介意这是否意味着我必须使用不同的类型而不是列表。

编辑:抱歉,忘了说我正在使用 .Net2.0,无法移动到 .Net 3.5。

I have a DataSource in my control which is always a List<T> where T has to inherit from IEntity.

public class MyClass<T> where T : IEntity
{
    public List<T> DataSource
    {
        get;
        set;
    }
}

Now, obviously you can't cast a List<T> to a List<IEntity> doing the following:

List<IEntity> wontWork = (List<IEntity>)this.DataSource;

How can I get the DataSource as a List of IEntity, whilst still being able to add and remove items from the DataSource? I.e. I could do the following, but removing from the List it returns would not remove from the DataSource:

public List<TOut> GetDataSourceCopyAsUnderlyingType<TOut>()
{

    if (this.DataSource == null)
    {
        return new List<TOut>();
    }
    else
    {

        // Get the list and the enumerator
        IList list = (IList)this.DataSource;
        IEnumerator enumerator = list.GetEnumerator();

        // Build the target list
        List<TOut> targetList = new List<TOut>();

        int i = 0;
        while (enumerator.MoveNext())
        {
            TOut entity = (TOut)list[i];
            targetList.Add(entity);
            i++;
        }

        return targetList;

        }

    }

Basically, I need some way of doing the following:

List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>();
int dataSourceCount = this.DataSource.Count;   // Equals 5
int interfaceCount = interfaceList.Count;      // Equals 5

interfaceList.RemoveAt(0);
int dataSourceCount = this.DataSource.Count;   // Equals 4
int interfaceCount = interfaceList.Count;      // Equals 4

And just to add, I don't mind if it means I've got to use a different type instead of a List.

EDIT: Sorry, forgot to say I'm using .Net2.0 and cannot move to .Net 3.5.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一身骄傲 2024-08-20 11:00:22

DrPizza 所说的,但有更多代码:

public class ListFacade<TIn, TOut> : IList<TOut> where TIn : TOut
{
    private readonly IList<TIn> innerList;

    public ListFacade(IList<TIn> innerList)
    {
        this.innerList = innerList;
    }

    public int Count
    {
        get { return this.innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return this.innerList.IsReadOnly; }
    }

    public TOut this[int index]
    {
        get { return this.innerList[index]; }
        set { this.innerList[index] = (TIn)value; }
    }

    public void Add(TOut item)
    {
        this.innerList.Add((TIn)item);
    }

    public void Clear()
    {
        this.innerList.Clear();
    }

    public bool Contains(TOut item)
    {
        return (item is TIn) && this.innerList.Contains((TIn)item);
    }

    public void CopyTo(TOut[] array, int arrayIndex)
    {
        var inArray = new TIn[this.innerList.Count];
        this.innerList.CopyTo(inArray, arrayIndex);
        Array.Copy(inArray, array, inArray.Length);
    }

    public IEnumerator<TOut> GetEnumerator()
    {
        foreach (var item in this.innerList)
        {
            yield return item;
        }
    }

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

    public int IndexOf(TOut item)
    {
        return (item is TIn) ? this.innerList.IndexOf((TIn)item) : -1;
    }

    public void Insert(int index, TOut item)
    {
        this.innerList.Insert(index, (TIn)item);
    }

    public bool Remove(TOut item)
    {
        return (item is TIn) && this.innerList.Remove((TIn)item);
    }

    public void RemoveAt(int index)
    {
        this.innerList.RemoveAt(index);
    }

如果参数不是 TIn 类型,则添加、插入和索引器集将会崩溃。

What DrPizza said, but with more code:

public class ListFacade<TIn, TOut> : IList<TOut> where TIn : TOut
{
    private readonly IList<TIn> innerList;

    public ListFacade(IList<TIn> innerList)
    {
        this.innerList = innerList;
    }

    public int Count
    {
        get { return this.innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return this.innerList.IsReadOnly; }
    }

    public TOut this[int index]
    {
        get { return this.innerList[index]; }
        set { this.innerList[index] = (TIn)value; }
    }

    public void Add(TOut item)
    {
        this.innerList.Add((TIn)item);
    }

    public void Clear()
    {
        this.innerList.Clear();
    }

    public bool Contains(TOut item)
    {
        return (item is TIn) && this.innerList.Contains((TIn)item);
    }

    public void CopyTo(TOut[] array, int arrayIndex)
    {
        var inArray = new TIn[this.innerList.Count];
        this.innerList.CopyTo(inArray, arrayIndex);
        Array.Copy(inArray, array, inArray.Length);
    }

    public IEnumerator<TOut> GetEnumerator()
    {
        foreach (var item in this.innerList)
        {
            yield return item;
        }
    }

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

    public int IndexOf(TOut item)
    {
        return (item is TIn) ? this.innerList.IndexOf((TIn)item) : -1;
    }

    public void Insert(int index, TOut item)
    {
        this.innerList.Insert(index, (TIn)item);
    }

    public bool Remove(TOut item)
    {
        return (item is TIn) && this.innerList.Remove((TIn)item);
    }

    public void RemoveAt(int index)
    {
        this.innerList.RemoveAt(index);
    }

Add, Insert and the indexer set will blow up if the argument is not of type TIn.

仙女 2024-08-20 11:00:22

好吧,这可能完全不是重点,但是,使用一点 Linq 怎么样?

var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);

这样你就可以轻松地转换objectList。
希望这有助于找到解决方案......

ok this might be completely beside the point but, how about using a little bit of Linq?

var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);

this way you can cast the objectList easily.
hope this helps to find the solution...

风铃鹿 2024-08-20 11:00:22

我也赞成 linq,但你可以这样做:

var interfaceList = objectList.Cast<IEntity>();

更短且更具表现力。

I'm in favor of linq too, but you can do it like:

var interfaceList = objectList.Cast<IEntity>();

Which is shorter and more expressive.

小情绪 2024-08-20 11:00:21

如果允许这样做,那将是一个非常糟糕的主意,这就是为什么不允许这样做。我可以将任何旧的 IEntity 添加到 List 中,如果该 IEntity 无法转换为 T,该列表将会爆炸。虽然所有 T 都是 IEntities,但并非所有 IEntities 都是 T。

这适用于数组,因为数组有一个故意的子类型漏洞(就像在 Java 中一样)。集合没有子类型漏洞。

It would be a monumentally bad idea if this were allowed, which is why it isn't. I can add any old IEntity to a List<IEntity> which will blow up if that IEntity can't be cast to T. Whilst all Ts are IEntities, not all IEntities are Ts.

This works with arrays because arrays have a deliberate subtyping hole (as they do in Java). Collections do not have a subtyping hole.

笑着哭最痛 2024-08-20 11:00:21

创建一个无缝转换的包装类。未经测试的示例:

public class CastList<TTarget, TOriginal> 
  : IList<TTarget> where TOriginal : TTarget
{
  List<TOriginal> _orig;
  public CastList(List<TOriginal> orig) { _orig = orig; }

  public Add(TTarget item) { _orig.Add(item); }

  public TTarget this[int i] 
  {
    get { return (TTarget)_orig[i]; }
    set { _orig[i] = value; }
  }

  public IEnumerator<TTarget> GetEnumerator() 
  {
     foreach(TOriginal item in _orig)
       yield return (TTarget)item;
  }

  // etc...
}

对原始列表的操作也将反映在包装器中。要使用它,只需使用您的数据源构建它即可。

Create a wrapper class that seamlessly converts. Untested sample:

public class CastList<TTarget, TOriginal> 
  : IList<TTarget> where TOriginal : TTarget
{
  List<TOriginal> _orig;
  public CastList(List<TOriginal> orig) { _orig = orig; }

  public Add(TTarget item) { _orig.Add(item); }

  public TTarget this[int i] 
  {
    get { return (TTarget)_orig[i]; }
    set { _orig[i] = value; }
  }

  public IEnumerator<TTarget> GetEnumerator() 
  {
     foreach(TOriginal item in _orig)
       yield return (TTarget)item;
  }

  // etc...
}

Manipulations of the original list will also be reflected in the wrapper. To use this, just construct it with your DataSource.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文