【问题标题】:Getting a fully qualified type name from a string .Net C#从字符串中获取完全限定的类型名称.Net C#
【发布时间】:2010-08-29 06:49:40
【问题描述】:

我有一个字符串,例如“Int”、“Double”、“DateTime”等。如何从该字符串中获取完全限定名称?

【问题讨论】:

  • 为什么需要全限定名?也许如果您提供一些额外的信息,我们可以提供更好的答案。

标签: c# .net


【解决方案1】:

值得注意的是int 不是一个类型。它是 C# 为类型 System.Int32 提供的别名。牢记这一点,并假设您只关心核心类型,您可以尝试:

var typeName = "DateTime";

var systemTypesAssembly = Assembly.Load("mscorlib");

var type = (from t in systemTypesAssembly.GetTypes()
           where t.Name == typeName
           select t).FirstOrDefault();

Console.WriteLine(type.FullName);

正如我所说,这不会适用于Int,但适用于Int32,这是它的别名类型。 此代码也不包含错误处理,例如,在 mscorlib 中找不到与您在typeName中输入的类型匹配的类型

【讨论】:

  • 当您不检查 type 是否为空时,通常最好使用 .First(),因为它会立即抛出一个有意义的异常,而不是稍后抛出一个无意义的 NullReferenceException .
  • 谢谢,我知道 int 绝对不是一种类型,但我可以将得到的字符串映射到 Int32。因为现在我只需要内置类型,我可以使用你的方法。
  • @Martinho,在这种情况下,我确切地知道 null 是什么(/为什么),但公平点 =)
  • @user114385,很高兴我能帮上忙!希望这意味着这正在成为公认的答案吗? ;=)
  • @userrandomnumber:如果您还想支持 C# 简写,只需将简写映射到完整类型名称的字典添加到此代码即可。 MSDN 中应提供完整的简写类型名称列表。
【解决方案2】:

在进一步讨论之前,我想指出 .NET Framework 基类库中没有名为 Int 的类。有System.Int32,在C#中恰好有一个别名:int

您可以通过多种方式做到这一点。

一种简单但有限的方法是使用字典将字符串映射到相应的 FQN:

public static IDictionary<string, string> FqnMap = new Dictionary<string, string>
{
    { "Int", "System.Int32" },
    { "Double", "System.Double" },
    { "DateTime", "System.DateTime" },
};

public string GetFqn(string name)
{
    return FqnMap[name]; // TODO: add error handling
}

一种更复杂但更强大的方法是使用reflection 从一组程序集中搜索所有类型。像这样的:

public class FqnResolver
{
    public FqnResolver(IEnumerable<Assembly> assemblies)
    {
        Assemblies = new List<Assembly>(assemblies);
    }
    public FqnResolver(params Assembly[] assemblies) : this(assemblies as IEnumerable<Assembly>) { }
    public FqnResolver() : this(new Assembly[0]) { }

    public ICollection<Assembly> Assemblies { get; private set; }

    public string GetFqn(string name)
    {
        var candidates = from a in Assemblies
                         from t in a.GetTypes()
                         where t.Name == name
                         select t.FullName;
        return candidates.First(); // will throw if no valid type was found
                                   // and does not count duplicates
    }
}

【讨论】:

  • 您不需要在第二个 ctor 中强制转换为 IEnumerable
  • @dfowler:显然我愿意。快速检查 LinqPad 产生:“构造函数 'UserQuery.FqnResolver.FqnResolver(params System.Reflection.Assembly[])' 不能调用自身”。我真的需要强制转换来强制编译器选择第一个 ctor,而不是递归构造函数调用。另外,我认为编译器不会发出任何强制转换,而是直接调用另一个 ctor,但我必须确认这一点。
【解决方案3】:

这在 .Net 中并不是真正可行的。为了获得一个类型的完全限定名称,您需要方便地使用Type 对象。为了获得Type 对象,您通常需要一个实例、完全限定名称,或者您必须进行一些搜索。

后者有效,但效率不高,因为您需要搜索每个程序集并输入已加载的 AppDomain 以找到正确答案。

foreach ( var assembly in AppDommain.CurrentDomain.GetAssemblies() ) {
  foreach ( var type in assembly.GetTypes() ) {
    if ( type.Name == target ) {
      return type.FullName;
    }
  }
}

尽管如此,此解决方案仍不能 100% 为您工作。主要是因为 .Net 框架中没有类型“Int”。它的实际类型名称是“Int32”。

【讨论】:

    【解决方案4】:

    像“String”这样的类型名称可能不明确,因为它可能引用System.StringFooAssembly.String,因此您必须搜索所有已加载程序集中的所有类型,这可能会产生多个结果。这一点反射可能很慢,但您可以以内存为代价进行缓存结果的明显优化:

    static void Main(string[] args)
    {
        string typeName = "String";
        foreach (var type in GetFullType(typeName))
        {
            Console.WriteLine(type.FullName);
        }
    }
    
    static IEnumerable<Type> GetFullType(string className)
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var type in assembly.GetTypes())
            {
                if (type.Name.Equals(className, StringComparison.OrdinalIgnoreCase))
                {
                    yield return type;
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-20
      • 2021-03-25
      • 2014-06-04
      • 2014-01-13
      • 1970-01-01
      • 1970-01-01
      • 2016-09-30
      • 1970-01-01
      相关资源
      最近更新 更多