如果我有一个类型的字符串表示,例如"List<string>"
或"int"
...
有没有办法检查这是否是真正的.net类型?
例如,如果我有"List<Crap>"
,那么我想返回false,因为Crap
不是.net中的真实类型。如果我有"string"
或"Dictionary<string, object>"
,那么我想返回true。
这可能吗?
感谢。
答案 0 :(得分:0)
如果您确定对象不可为空,则可以使用
item.GetType().Namespace.StartsWith("System")
如果不是,您只需创建一个系统对象列表,然后检查您的对象是否在该列表中
List<Type> sysTypes = Assembly.GetExecutingAssembly()
.GetType().Module.Assembly.GetExportedTypes().ToList();
if (sysTypes.Contains(item.GetType())) {
// do something usefull
}
答案 1 :(得分:-1)
e.g:
string typeString = "System.String";
if(Type.GetType(typeString) != null)
{
//It's a real type
}
编辑:有一点需要注意,如果类型不在当前程序集中,则必须使用assembly qualified name完全限定类型。
EDIT2:借鉴Amson的答案:
var types = Assembly.GetExecutingAssembly().GetType().Module.Assembly.GetExportedTypes()
bool isReal = types.Any(x=>x.FullName == typeString);
然而,这仍然需要一些字符串操作来处理泛型。由于List<String>.FullName
是:
System.Collections.Generic.List`1 [[System.String,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]`
EDIT3:在字符串操作方面,我提出了这个问题,从Dictionary<string,List<string>>
开始作为基础:
Type type2 = typeof(Dictionary<string, List<string>>);
string typeString = type2.FullName;
int endOfType = typeString.IndexOf('`');
string mainType = typeString.Substring(0,endOfType);
mainType = mainType.Split('.').Last(); // this equals "Dictionary"
var genString = typeString.Substring(endOfType + 3);
string[] generics = genString.Split('[', ']');
generics = generics.Where(s => s != "" && s!= ",").ToArray();
它还没有出现在泛型上(虽然它也不是太),但我们现在至少可以比较基类型了! (虽然我们还需要在这里检查是否有 no 泛型参数)。
如果我管理解决方案,我今晚晚些时候会对此进行更新。
EDIT4.5:成功(等等)!!!
以下代码会将Type.FullName中的值转换为人类可读的内容:
/// <summary>
/// Converts a type's full name into a human readable string
/// </summary>
/// <param name="type">The type to convert</param>
/// <returns>Type formatted as follows: Dictionary<List<String>,Queue<Int32>>
/// Or for an open generic (e.g. Action<,>) returns Action<,></returns>
private static string ConvertTypeToReadableString(Type type)
{
string typeString = type.FullName;
int endOfType = 0;
if (typeString.Contains('`'))
{
//We have generic arguments
endOfType = typeString.IndexOf('`');
string mainType = typeString.Substring(0, endOfType);
mainType = mainType.Split('.').Last(); // this equals "Dictionary"
//Use this for namespace qualified names instead:
//return typeString
string result = mainType + "<";
var genString = typeString.Substring(endOfType + 3);
//Get number of generic arguments to expect.
int argCount = 0;
int tempArgCount = 0;
int i = 1;
while (i <= genString.Length && Int32.TryParse(genString.Substring(0, i), out tempArgCount))
{
i++;
argCount = tempArgCount;
}
string[] generics = genString.Split('[', ']');
generics = generics.Where(s => s != "" && s != "," && !s.StartsWith(",")).ToArray();
if (generics.Length < argCount)
{
//Assume an open generic
for(int x= 0; x< argCount-1; x++)
{
result += ",";
}
result += ">";
}
else
{
result += ParseGenerics(generics, argCount) + ">";
}
return result;
}
else
{
//No generic arguments
return typeString.Split('.').Last();
//Use this for namespace qualified names instead:
//return typeString;
}
}
/// <summary>
/// Convert generic arguments into simplified strings
/// </summary>
/// <param name="generics">List of strings, each containing one generic argument.</param>
/// <returns>Single string of format Item1,Item2,Item3<Item4,Item5></returns>
public static string ParseGenerics(string[] generics, int genericArgs)
{
string result = "";
int index = 0;
while(genericArgs > 0)
{
string generic = generics[index];
if (generic.Contains('`'))
{
//Another generic
int genericIndex = generic.IndexOf('`');
string mainType = generic.Substring(0, genericIndex).Split('.').Last();
//Use this if you want namespace-qualified names:
//string mainType = generic.Substring(0,genericIndex);
int i = 1;
//Get number of generic arguments to expect.
int argCount = 0;
int tempArgCount = 0;
while (genericIndex + 1 + i <= generic.Length && Int32.TryParse(generic.Substring(genericIndex + 1, i), out tempArgCount))
{
i++;
argCount = tempArgCount;
}
//Parse internal generics
result += mainType + "<" + ParseGenerics(generics.Skip(index + 1).ToArray(),argCount) + ">";
index += argCount;
}
else
{
//Get type name
result += generic.Split(',').First().Split('.').Last();
//Use this if you want namespace-qualified names:
//result += generic.Split(',').First();
}
result += ",";
genericArgs--;
index++;
}
//remove trailing comma
return result.Substring(0, result.Length - 1);
}
样本用法:
bool isRealType = false;
string typeString = "Dictionary<string,List<string>>".Replace(" ", string.empty).ToLowerInvariant();
var types = Assembly.GetExecutingAssembly().GetType().Module.Assembly.GetExportedTypes();
isRealType = types.Any(t=> ConvertTypeToReadableString(t).ToLowerInvariant().Equals(typeString));
如果您希望将名称空间限定名称放入(例如System.String而不是String),请取消注释相关注释。
在此之后您可能想要做的唯一事情是使用查找表将整数类型转换为它们的类名(例如int到Int32),但我将其作为练习留给您。
编辑5:剩下的一个问题。我的答案现在适用于转换,即使使用开放的泛型类型,但您仍需要考虑Assembly.GetExecutingAssembly().GetType().Module.Assembly.GetExportedTypes();
仅返回开放泛型的事实,并检查您是否拥有正确数量的args你的字符串。从我在这里得到的东西非常可行,但我必须睡觉。