【问题标题】:Getting the fully qualified name of a type from a TypeInfo object从 TypeInfo 对象获取类型的完全限定名称
【发布时间】:2017-03-28 22:49:25
【问题描述】:

是否有可能获得包含在 TypeInfo 对象中的类型的完全限定名称?

在调试器中,许多这些值很好地显示为System.Int32,但是当它被打印出来时,没有一个包含这个完全限定的名称。我需要将此作为参数提供给Type.GetType()

var typeInfo = semanticModel.GetTypeInfo(argument);
var w = typeInfo.ToString(); // Microsoft.CodeAnalysis.TypeInfo
var y = typeInfo.Type.ToString(); // int
var z = typeInfo.Type.ToDisplayString(); // int 
var a = typeInfo.Type.OriginalDefinition.ToDisplayString(); // int
var b = typeInfo.Type.OriginalDefinition.ToString(); // int
var c = typeInfo.Type.Name; // Int32
var d = typeInfo.Type.MetadataName; // Int32
var e = typeInfo.Type.ToDisplayParts(); // {int}
var f = typeInfo.Type.ContainingNamespace; // System

请注意,这应该适用于每种类型,所以我不能只是将命名空间与名称连接起来。

或者:是否有另一种(更合适的?)方法来获得确切的类型?

对于上下文:我想检查一个类的类型参数是否包含一些特定的方法。因此,我的方法是从TypeArgumentListSyntax 获取参数并从每个TypeSyntax 对象获取TypeInfo

【问题讨论】:

    标签: c# roslyn


    【解决方案1】:

    ToDisplayString 方法允许您传入一个“格式”对象,该对象具有大量选项来控制您希望如何格式化内容:

    var symbolDisplayFormat = new SymbolDisplayFormat(
        typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
    
    string fullyQualifiedName = typeSymbol.ToDisplayString(symbolDisplayFormat);
    

    您获取诸如“int”之类的关键字是默认格式的原因是包含SymbolDisplayMiscellaneousOptions.UseSpecialTypes 标志,该标志指定将语言关键字用于特殊类型而不是常规名称。

    【讨论】:

    • 这确实有效,谢谢!不过,我有一个附带问题:Type.GetType(Tuple) 没有给我Tuple<int, int>Type,而这些在我的情况下并不相同。据我所知,我无法将任何类型参数传递给Type.GetType(string)(又名:Type.GetType("Tuple<int, int>")),在这里获得正确类型的最佳选择是什么?
    • 您必须以 CLR 形式传递类型参数,使用方括号和其他一些东西。老实说,这是 Roslyn 不具备使这一切变得容易所需的 API 的一个地方。 :-(
    • 是的,如果TypeInfo 对象引用了确切的Type(我希望它会这样做),那将对我的代码的可读性产生很大影响。使用 tickform 符号可以正常工作,但仅适用于内置类型。即使我将包含程序集添加到字符串中,它也无法找到我自己定义的类。为了获得用户定义的类型,我还应该做些什么吗?
    • 好吧,所以为 TypeInfo 获取一个类型,除了命名问题之外,是一个棘手的问题。它假定您有一个可以加载和找到的程序集。当您进行构建时,编译器可能正在加载本身不能作为“正常”程序集加载的引用程序集。即使它们是,您也可能必须挂钩 AppDomain.AssemblyResolve 以定位您的引用以及您构建的任何程序集。
    • “构建”和“运行时”是真正不同的领域,从一个到另一个的交叉定义不明确,充其量。我在这里假设您确实需要 System.Type,因为您正在使用其他一些反射 API,或者尝试加载该类型并从中执行代码。
    【解决方案2】:

    我也找不到内置的东西,而且我很确定这不是最优雅的方式,但它对我来说可以像这样构造一个合格的类型名称:

    private static string GetQualifiedTypeName(ISymbol symbol)
    {
        return symbol.ContainingNamespace 
            + "." + symbol.Name 
            + ", " + symbol.ContainingAssembly;
    }
    

    如果您不需要程序集限定类型名称,请不要在最后一行的末尾连接 ContainingAssembly

    【讨论】:

    • 好吧,很明显我误解了命名空间,实际上这个看起来应该可以工作:例如它返回给我RoslynTester.Collections.MyTestClass, RoslynTester, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null。但是,当我将其与 Type.GetType() 结合使用时,将返回 null 值。为什么找不到这个?
    • 您好,必须将包含您的自定义类型的程序集加载到您的程序中,对 Type.GetType(..) 进行解析才能在运行时“了解”您的类型。
    • Mhhm 好点,虽然Assembly.Load(symbol.ContainingAssembly) 只向我抛出了一个异常,说它无法“加载文件或程序集 或其依赖项之一。系统找不到指定的文件。”我当然希望它找到一个程序集,我通过 Roslyn 本身获得了字符串表示。
    • 这对我有用,但我必须使用 MetadataName 而不是 Name
    【解决方案3】:

    使用语义模型,您也可以像我在这里所做的那样:

    var typeInfo = context.SemanticModel.GetTypeInfo(identifierNameSyntax);
    var namedType = typeInfo.Type as INamedTypeSymbol;
    if (namedType != null && namedType.Name == nameof(ConfiguredTaskAwaitable) && GetFullNamespace(namedType) == typeof(ConfiguredTaskAwaitable).Namespace)
        return true;
    

    “GetFullNamespace”的工作方式如下:

        public static IEnumerable<string> GetNamespaces(INamedTypeSymbol symbol)
        {
            var current = symbol.ContainingNamespace;
            while (current != null)
            {
                if (current.IsGlobalNamespace)
                    break;
                yield return current.Name;
                current = current.ContainingNamespace;
            }
        }
    
        public static string GetFullNamespace(INamedTypeSymbol symbol)
        {
            return string.Join(".", GetNamespaces(symbol).Reverse());
        }
    
        public static string GetFullTypeName(INamedTypeSymbol symbol)
        {
            return string.Join(".", GetNamespaces(symbol).Reverse().Concat(new []{ symbol.Name }));
        }
    

    显然 Jason Malinowski 的回答对于简单的情况更方便

    【讨论】:

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