简而言之,我需要在编译时不知道IEnumerable list
将IEnumerable<T>
(值HashSet<T> set
)转换为T
。我认为可以做到的唯一方法如下,但我发现它非常难看。
public IEnumerable GetHashSet(IEnumerable source)
{
Type itemType = source.GetType().GetGenericArguments()[0];
Type listOpen = typeof(List<>);
Type listClosed = listOpen.MakeGenericType(new Type[] { itemType });
IList list = Activator.CreateInstance(listClosed) as IList;
foreach (var obj in source)
list.Add(obj);
Type hashSetOpen = typeof(HashSet<>);
Type hashSetClosed = hashSetOpen.MakeGenericType(new Type[] { itemType });
return Activator.CreateInstance(hashSetClosed, list) as IEnumerable;
}
问题是,HashSet<T>
无法通过某些非通用接口添加对象(相反,List<T>
具有IList.Add(object)
)。它也没有一个带有“裸”IEnumerable的构造函数(List<T>
也没有)。
答案 0 :(得分:6)
这应该这样做:
public IEnumerable<T> GetHashSet<T>(IEnumerable<T> source)
{
return new HashSet<T>(source);
}
答案 1 :(得分:5)
原始回答: 如果你想坚持你的方法签名,你可以这样做:
private static IEnumerable GetHashSet(IEnumerable source)
{
var type = source.GetType().GetGenericArguments()[0];
var ctor = typeof(HashSet<>).MakeGenericType(type)
.GetConstructor(new[] {typeof (IEnumerable<>).MakeGenericType(type)});
return ctor.Invoke(new object[] { source }) as IEnumerable;
}
<强>改进:强> 正如评论中所提到的,通常最好更明确地说明函数应该做什么,所以我添加了必要的检查:
private static IEnumerable GetHashSet(IEnumerable source)
{
var inputType = source.GetType();
if (!inputType.IsGenericType || inputType.IsGenericTypeDefinition)
throw new ArgumentException(nameof(source));
var genericArgumentType = inputType.GetGenericArguments()[0];
var iEnumerableType = typeof (IEnumerable<>).MakeGenericType(genericArgumentType);
if (!iEnumerableType.IsAssignableFrom(inputType))
throw new ArgumentException(nameof(source));
var ctor = typeof (HashSet<>).MakeGenericType(genericArgumentType)
.GetConstructor(new[] {iEnumerableType});
if (ctor == null)
throw new Exception("ctor not found.");
return ctor.Invoke(new object[] { source }) as IEnumerable;
}