我想实现一个集合,其项目需要进行空虚测试。 在引用类型的情况下,将测试为null。对于值类型,必须实现空测试,并且可能选择表示空白的特定值。
我的T的通用集合应该可用于值和引用类型值(意味着Coll<MyCalss>
和Coll<int>
都应该是可能的。但我必须以不同方式测试参考和值类型。
有一个实现IsEmpty()方法的接口,从我的泛型类型中排除这个逻辑,这不是很好吗?但是,当然,这个IsEmpty()方法不能是成员函数:它不能在空对象上调用。
我找到的一个解决方法是将收集项目存储为对象,而不是T-s,但它让我头疼(围绕拳击和强类型)。在旧的C ++中,没有问题: - )
下面的代码演示了我想要实现的目标:
using System;
using System.Collections.Generic;
namespace StaticMethodInInterfaceDemo
{
public interface IEmpty<T>
{
static T GetEmpty(); // or static T Empty;
static bool IsEmpty(T ItemToTest);
}
public class Coll<T> where T : IEmpty<T>
{
protected T[] Items;
protected int Count;
public Coll(int Capacity)
{
this.Items = new T[Capacity];
this.Count = 0;
}
public void Remove(T ItemToRemove)
{
int Index = Find(ItemToRemove);
// Problem spot 1: This throws a compiler error: "Cannot convert null to type parameter 'T'
// because it could be a non-nullable value type. Consider using 'default(T)' instead."
this.Items[Index] = null;
// To overcome, I'd like to write this:
this.Items[Index] = T.Empty; // or T.GetEmpty(), whatever.
this.Count--;
}
public T[] ToArray()
{
T[] ret = new T[this.Count];
int TargetIndex = 0;
for(int Index = 0; Index < this.Items.GetLength(0); Index++)
{
T Item = this.Items[Index];
// Problem spot 2: This test is not correct for value types.
if (Item != null)
ret[TargetIndex++] = Item;
// I'd like to do this:
if (!T.IsEmpty(Item))
ret[TargetIndex++] = Item;
}
return ret;
}
protected int Find(T ItemToFind)
{
return 1; // Not implemented in the sample.
}
}
}
答案 0 :(得分:7)
您可以为名为IsEmpty的界面创建扩展方法。然后你可以先测试这个扩展方法中的'this'参数是否为空。
因此,你可以在对实现你的接口的类型的任何引用上调用IsEmpty方法,而不是关于它是否为null。
答案 1 :(得分:3)
您可以使用'default'关键字,如:
this.Items[Index] = default(T);
答案 2 :(得分:3)
没有这样的东西是一个“空”int
,所以支持int
将是棘手的,除非你存储了一个定义的位图 - 但是如果您只需使用int?
的集合(即Nullable<int>
)为您完成。没有额外的工作,没有拳击:
List<int?> list1 = ...; // data
List<string> list2 = ...; // data
Console.WriteLine(list1[3]; == null); // actually maps to `item.HasValue`
Console.WriteLine(list2[3]; == null); // reference test
要从int
获取int?
,请执行以下任何操作:
int i = (int)value; // throws exception if empty
int i = i.Value; // throws exception if empty
int i = i.GetValueOrDefault(); // returns 0 if empty
如果您不需要能够测试为空,只需List<int>
(无?
)。没有额外的代码。没有特别的收藏类。它适用于大多数事情。
答案 3 :(得分:0)
不使用类中的数组来表示集合,而是使用堆栈或列表。那么你没有空索引,如果它们被删除,它们就不存在。
答案 4 :(得分:0)
如何在构造函数中发送两个函数?
public Coll(Func<T> createEmpty, Func<T, bool> isEmpty)
{
this.createEmpty = createEmpty;
this.isEmpty = isEmpty;
}
然后您可以稍后使用这些功能:
if (!isEmpty(item))
Items[index] = createEmpty();