C# C-列表是否可以无缝转换为列表或类似文件?
我的控件中有一个数据源,它始终是一个列表,T必须从该列表继承 基本上,我需要一些方法来完成以下工作:C# C-列表是否可以无缝转换为列表或类似文件?,c#,generics,list,.net-2.0,casting,C#,Generics,List,.net 2.0,Casting,我的控件中有一个数据源,它始终是一个列表,T必须从该列表继承 基本上,我需要一些方法来完成以下工作: List<IEntity> wontWork = (List<IEntity>)this.DataSource; List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>(); int dataSourceCount = this.DataSource.Count
List<IEntity> wontWork = (List<IEntity>)this.DataSource;
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,无法移动到.NET3.5。好的,这可能完全不重要,但是,使用一点Linq怎么样
var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);
这样,您可以轻松地强制转换objectList。
希望这有助于找到解决方案……我也支持linq,但您可以这样做:
var interfaceList = objectList.Cast<IEntity>();
如果允许这样做,那将是一个非常糟糕的主意,这就是为什么不允许这样做。我可以将任何旧的元素添加到一个列表中,如果该元素不能被转换为t,该列表将爆炸。虽然所有的t都是元素,但并非所有的元素都是t
这适用于数组,因为数组像在Java中一样,有一个故意的子类型漏洞。集合没有子类型孔。创建无缝转换的包装类。未经测试的样本:
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...
}
原始列表的操作也将反映在包装器中。要使用它,只需使用您的数据源构建它。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类型,则Add、Insert和indexer集将爆炸。对不起,我使用的是.Net2.0,我忘了指定。@Roel,@GenericTypeTea:ConvertAll与LINQ无关,它是列表本身的一个方法,在.Net2中可用,但如果没有C3,则需要使用旧的委托语法,而不是lambda。但是ConvertAll并不满足要求,因为它返回一个新列表,而不是对现有列表进行就地转换。感谢您的解释。我知道ConvertAll存在于列表中,但我已经尝试过了,并且知道它不符合您所指出的我的要求;除了别的,你应该考虑将数据源改为ILIST而不是列表。@ DrPizza,+ 1,我第一次听到.NET程序员说的话!我正在使用.Net2.0。因此我不能使用linq。@klausbyskov:这不符合要求,因为它返回一个新列表,而不是对现有列表进行就地转换。嗯,好的。。。然后嗯。。。你能把它扔给一个数不清的人吗?我有一些代码正是这样做的,这是有效的。。。但我在这里的.NET4国家,所以我不知道是否有一些新的和闪光的东西,我不知道。啊,当然。对于你为什么不能这样做,现在有了完美的解释。谢谢你的建议。关于我能做些什么,有什么建议吗?复制到列表中,然后再复制回来。如果您不需要可扩展性,只需更换元素就可以了。虽然没有数组子类型漏洞那么糟糕,但我仍然不确定这是否真的应该鼓励。我认为这取决于用例。我不建议这样设计一个框架,但如果它只是将一些类粘在一起的一个实现细节,为什么不呢?我真正的问题是,为什么DataSource不只是一个列表呢?如果他想把它们当作简单的工具,而不使用任何特定于T的方法,那么首先将它们存储在列表中似乎更容易。
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...
}
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);
}