我正在使用一种方法,当传递List<List<int>>
时将返回{int}
,传递时double[,]
将返回{double}
,传递Dictionary<string, byte[]>
时将返回{string, byte}
等等。基本上,它是关于递归输入类型,直到找到的类型不再是“容器类型”,然后报告这种“基本”类型。
我最初的猜测是测试IEnumerable
实现的输入类型,但这似乎不起作用。我也对GetNestedTypes()
做了一些试验和错误,但这似乎是无关的。我最终得到了以下方法,它取决于ICollection
。我扔了一些非常奇怪的类型,它似乎工作;我想知道的是,该方法是否覆盖了那里的所有容器类型,或者它是否遗漏了某些东西(即它实际上是否有效或者我的测试结果是“快乐的巧合”?)
非常感谢。
编辑(1):如果通过,比如Dictionary<Foo, Bar>
,方法返回{Foo, Bar}
是可以的,无论这些类型的内部结构如何(它不需要超出)。
public void GetPrimitiveTypes(Type inputType, ref List<Type> primitiveTypes)
{
if (inputType.IsGenericType)
foreach (Type genericArg in inputType.GetGenericArguments())
GetPrimitiveTypes(genericArg, ref primitiveTypes);
if (inputType.IsArray)
GetPrimitiveTypes(inputType.GetElementType(), ref primitiveTypes);
if (inputType.GetInterface("ICollection") == null)
primitiveTypes.Add(inputType);
}
编辑(2):这是一个改进的版本(我相信)。它执行一些错误处理并用IsArray
替换HasElementType
(来自Josh的回答)。我也决定留下指针。除了空和指针,假设是:(1)所有“容器”类型实现ICollection
和(2)实现ICollection
的所有类型都是通用的或具有元素类型。如果这些假设是正确的,那么我认为下面的方法应该有效,但这是我不确定的。我在问题中也用“基本”取代了“原始”,因为“原始”有其自己的不同含义。
public void GetPrimitiveTypes2(Type inputType, ref List<Type> primitiveTypes)
{
// Handle null
if (inputType == null)
throw new ArgumentNullException("inputType");
// Leave pointers out
if (inputType.IsPointer)
throw new ArgumentException(message: "Pointer types are not supported", paramName: "inputType");
// Option 1: type is generic
if (inputType.IsGenericType)
{
foreach (Type genericArg in inputType.GetGenericArguments())
GetPrimitiveTypes2(genericArg, ref primitiveTypes);
return;
}
// Option 2: type has element type
if (inputType.HasElementType)
{
GetPrimitiveTypes2(inputType.GetElementType(), ref primitiveTypes);
return;
}
// Option 3: type is not a container
// Remark: can't use IsPrimitive as it will be false for, say, type Foo
if (inputType.GetInterface("ICollection") == null)
{
primitiveTypes.Add(inputType);
return;
}
// Do options 1-3 above cover all cases?
throw new ArgumentException(message: "Unhandled type", paramName: "inputType");
}
答案 0 :(得分:1)
这是我使用的方法。你会发现它和你的没什么不同。但它不处理具有多个类型参数的泛型。
/// <summary>
/// When given certain types such as those based on <see cref="T:Nullable`1"/>, <see cref="T:IEnumerable`1"/>,
/// or <see cref="T:Array"/>, returns the element type associated with the input type.
/// </summary>
/// <remarks>
/// For example, calling this method with Nullable(Of Boolean) would return Boolean. Passing Int32[] would
/// return Int32, etc. All other types will return the input.
/// </remarks>
/// <param name="type">The a nullable type, array type, etc. whose element type you want to retrieve.</param>
/// <returns>The type that the input type is based on.</returns>
public static Type GetElementType( Type type )
{
ParameterValidation.ThrowIfNull( type, "type" );
if ( type.IsGenericType ) {
var typeArgs = type.GetGenericArguments( );
if ( typeArgs.Length == 1 ) {
return typeArgs[0];
} // if
} // if
if ( type.HasElementType ) {
return type.GetElementType( );
} // if
if ( type.IsEnum ) {
return Enum.GetUnderlyingType( type );
} // if
return type;
}
答案 1 :(得分:0)
以Josh的答案为基础,但更正术语并将结果限制为集合/枚举:
public static Type GetElementType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (type.HasElementType)
return type.GetElementType();
Type[] interfaces = type.GetInterfaces();
foreach (Type t in interfaces)
{
if (t.IsGenericType)
{
Type generic = t.GetGenericTypeDefinition();
if (generic == typeof(IEnumerable<>))
return t.GetGenericArguments()[0];
}
}
/* If you want to allow weakly typed collections (and just have element type
* Object), you can uncomment the following:
*/
//if (typeof(IEnumerable).IsAssignableFrom(type))
// return typeof(object);
return null;
}
public static Type GetUnderlyingType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (type.IsEnum)
return type.GetEnumUnderlyingType();
return Nullable.GetUnderlyingType(type);
}