如何检查字符串中的类型是否为真实类型

本文关键字:类型 是否 真实 字符串 何检查 检查 | 更新日期: 2023-09-27 18:01:14

如果我有一个类型的字符串表示,例如"List<string>""int"。。。

有没有办法检查这是否是一个真正的.net类型?

例如,如果我有"List<Crap>",那么我想返回false,因为Crap不是.net中的真实类型。如果我有"string""Dictionary<string, object>",那么我想要返回true。

这可能吗?

谢谢。

如何检查字符串中的类型是否为真实类型

如果您确定您的对象不可为null,则可以使用

item.GetType().Namespace.StartsWith("System")

如果没有,你可以创建一个系统对象列表,然后检查你的对象是否在列表中

 List<Type> sysTypes = Assembly.GetExecutingAssembly()
     .GetType().Module.Assembly.GetExportedTypes().ToList();
 if (sysTypes.Contains(item.GetType())) {
     // do something usefull
 }

使用Type.GetType

例如:

string typeString = "System.String";
if(Type.GetType(typeString) != null) 
{
    //It's a real type 
}

编辑:有一点需要注意,如果类型不在当前程序集中,则必须使用程序集限定名称对其进行完全限定。

第二版:借用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]]`

第三版:在字符串操作方面,我从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();

它还没有出现在泛型上(尽管它也不太(,但我们现在至少可以比较基本类型了!(尽管我们也需要在这里检查是否有没有通用参数(。

如果我能找到解决方案,我会在今晚晚些时候回家时更新。

第4.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(,但我把它留给你练习。

第五版:只剩下一个问题。我的答案现在可以很好地进行转换,即使是使用开放泛型类型,但您仍然需要考虑Assembly.GetExecutingAssembly().GetType().Module.Assembly.GetExportedTypes();将只返回开放泛型这一事实,并检查您的字符串中是否有正确数量的args。从我现在的情况来看,这是非常可行的,但我必须睡觉。