C# 如何优雅地转换IEnumerable<;T>;到HashSet<;T>;在运行时不事先知道T
简而言之,我需要将C# 如何优雅地转换IEnumerable<;T>;到HashSet<;T>;在运行时不事先知道T,c#,reflection,C#,Reflection,简而言之,我需要将IEnumerable列表(值为IEnumerable)转换为HashSet,而不需要在编译时知道T。我认为唯一可以做到的方法是如下所示,但我发现它非常难看 public IEnumerable GetHashSet(IEnumerable source) { Type itemType = source.GetType().GetGenericArguments()[0]; Type listOpen = typeof(List<>); T
IEnumerable列表
(值为IEnumerable
)转换为HashSet
,而不需要在编译时知道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;
}
public IEnumerable GetHashSet(IEnumerable源代码)
{
类型itemType=source.GetType().GetGenericArguments()[0];
类型listOpen=typeof(列表);
类型listClosed=listOpen.MakeGenericType(新类型[]{itemType});
IList list=Activator.CreateInstance(listClosed)作为IList;
foreach(源中的var obj)
列表。添加(obj);
类型hashSetOpen=typeof(HashSet);
类型hashSetClosed=hashSetOpen.MakeGenericType(新类型[]{itemType});
将Activator.CreateInstance(hashSetClosed,list)返回为IEnumerable;
}
问题是,HashSet
无法通过一些非通用接口添加对象(相反,List
具有IList.Add(object)
)。此外,它没有接受“裸”IEnumerable的构造函数(也没有List
) 这应该可以做到:
public IEnumerable<T> GetHashSet<T>(IEnumerable<T> source)
{
return new HashSet<T>(source);
}
public IEnumerable GetHashSet(IEnumerable源代码)
{
返回新的哈希集(源);
}
这应该可以做到:
public IEnumerable<T> GetHashSet<T>(IEnumerable<T> source)
{
return new HashSet<T>(source);
}
public IEnumerable GetHashSet(IEnumerable源代码)
{
返回新的哈希集(源);
}
原始答案:
如果您希望坚持方法签名,您可以这样做:
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;
}
私有静态IEnumerable GetHashSet(IEnumerable源)
{
var type=source.GetType().GetGenericArguments()[0];
var ctor=typeof(HashSet).MakeGenericType(type)
.GetConstructor(新[]{typeof(IEnumerable).MakeGenericType(type)});
将ctor.Invoke(新对象[]{source})作为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;
}
私有静态IEnumerable GetHashSet(IEnumerable源)
{
var inputType=source.GetType();
如果(!inputType.IsGenericType | | inputType.IsGenericTypeDefinition)
抛出新ArgumentException(nameof(source));
var genericArgumentType=inputType.GetGenericArguments()[0];
var iEnumerableType=typeof(IEnumerable);
如果(!iEnumerableType.IsAssignableFrom(inputType))
抛出新ArgumentException(nameof(source));
var-ctor=typeof(HashSet).MakeGenericType(genericArgumentType)
.GetConstructor(新[]{iEnumerableType});
if(ctor==null)
抛出新异常(“未找到ctor”);
将ctor.Invoke(新对象[]{source})作为IEnumerable返回;
}
原始答案:
如果您希望坚持方法签名,您可以这样做:
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;
}
私有静态IEnumerable GetHashSet(IEnumerable源)
{
var type=source.GetType().GetGenericArguments()[0];
var ctor=typeof(HashSet).MakeGenericType(type)
.GetConstructor(新[]{typeof(IEnumerable).MakeGenericType(type)});
将ctor.Invoke(新对象[]{source})作为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;
}
私有静态IEnumerable GetHashSet(IEnumerable源)
{
var inputType=source.GetType();
如果(!inputType.IsGenericType | | inputType.IsGenericTypeDefinition)
抛出新ArgumentException(nameof(source));
var genericArgumentType=inputType.GetGenericArguments()[0];
var iEnumerableType=typeof(IEnumerable);
如果(!iEnumerableType.IsAssignableFrom(inputType))
抛出新ArgumentException(nameof(source));
var-ctor=typeof(HashSet).MakeGenericType(genericArgumentType)
.GetConstructor(新[]{iEnumerableType});
if(ctor==null)
抛出新异常(“未找到ctor”);
将ctor.Invoke(新对象[]{source})作为IEnumerable返回;
}
为什么不将该方法设置为泛型(IEnumerable GetHashSet(IEnumerable source)
)?如果你不这样做,你就不得不采取这种“丑陋”的方法。还有,你真正的问题是“我怎样才能让这段代码不那么难看”?当然,您可以完全跳过列表,通过找到合适的add
方法,直接将source
中的项目添加到HashSet中。谢谢。编译时我不知道t,所以我不能使用带有此签名的方法,也不能使用Add
方法(因为,是什么类型)。看起来,您试图避免重复(因为您将哈希集返回为IEnumerable)。如果是这样的话,可以看看或。我建议您为ICollection
创建一个不安全的包装器,它实现ICollection
和强制转换。使用反射和内部集合创建此对象的实例,然后通过ICollection.Add
方法添加每个对象。@Oliver,谢谢,不是这样的。之所以使用HashSet,是因为EntityFramework 6似乎更喜欢实体上的集合。代码是针对一个非常一般的类的。CrudController,尝试将页面上任何多选列表中的字符串ID转换为EF实体上的更新关系,无论其类型如何。为什么不将该方法设置为泛型(IEnumerable GetHashSet(IEnumerable source)
)?如果你不这样做,你就不得不采取这种“丑陋”的方法。还有,你真正的问题是“我怎样才能让这段代码不那么难看”?当然,您可以完全跳过列表,通过找到合适的add
方法,直接将source
中的项目添加到HashSet中。谢谢。编译时我不知道t,所以我不能使用带有此签名的方法,也不能使用