【问题标题】:How to get full C# declaration for a Type?如何获得类型的完整 C# 声明?
【发布时间】:2009-06-17 08:07:03
【问题描述】:

我正在尝试编写一个函数来为 Type 对象生成完整的 C# 声明。我当前的方法涉及对 Type 对象执行非常手动和特定的逻辑。

.Net 是否有一些内置方法来生成此声明?

以这个类为例:

namespace My.Code.Here
{
   public class Class1<>
   {
      public enum Enum1 { }
   }
}

当在 typeof(Class1.Enum1) 上调用函数(我们称之为 getCSharpDec)时,它将返回“My.Code.Here.Class1.Enum1”。

【问题讨论】:

    标签: c# .net reflection types


    【解决方案1】:

    这里有几个问题...

    • C# 和 Type 以不同的方式命名嵌套类型
    • C# 和 Type 对泛型类型的命名不同

    顺便说一句,Class1&lt;&gt;.Enum1 不是封闭类型,但这不应该成为问题...

    (编辑)

    这已经非常接近了——不过,它仍然保留了该类型的外部泛型:

    static void Main()
    {
        Type t = typeof(My.Code.Here.Class1<>.Enum1);
        string s = GetCSharpName(t); // My.Code.Here.Class1<T>.Enum1<T>
    }
    
    public static string GetCSharpName<T>()
    {
        return GetCSharpName(typeof(T));
    }
    public static string GetCSharpName(Type type)
    {
        StringBuilder sb = new StringBuilder();
        sb.Insert(0, GetCSharpTypeName(type));
        while (type.IsNested)
        {
            type = type.DeclaringType;
            sb.Insert(0, GetCSharpTypeName(type) + ".");
    
        }
        if(!string.IsNullOrEmpty(type.Namespace)) {
            sb.Insert(0, type.Namespace + ".");
        }
        return sb.ToString();
    }
    private static string GetCSharpTypeName(Type type)
    {
    
        if (type.IsGenericTypeDefinition || type.IsGenericType)
        {
            StringBuilder sb = new StringBuilder();
            int cut = type.Name.IndexOf('`');
            sb.Append(cut > 0 ? type.Name.Substring(0, cut) : type.Name);
    
            Type[] genArgs = type.GetGenericArguments();
            if (genArgs.Length > 0)
            {
                sb.Append('<');
                for (int i = 0; i < genArgs.Length; i++)
                {
                    sb.Append(GetCSharpTypeName(genArgs[i]));
                    if (i > 0) sb.Append(',');
                }
                sb.Append('>');
            }
            return sb.ToString();
        }
        else
        {
            return type.Name;
        }
    }
    

    【讨论】:

    • 很好的例子,有很多潜在的特殊情况。需要注意的是,genArgs 上的 for 循环可以替换为 string.Join(",",genArgs.Select(x => x.FullName)。如果速度有所不同,我的猜测是 Marcs 代码可能更快,但为了可读性,我个人更喜欢单行而不是循环
    • 为了使它们在功能上等效,选择应该使用 GetCSharpTypeName(T) 而不是 .FullName
    • 感谢 Marc 的代码,您的代码看起来与我当前的代码非常相似。我希望找到一个不涉及特定复杂性的解决方案(或至少由外部函数包装:)
    • 别忘了Type 需要支持所有语言……而且它们总是共享很多语法……所以几乎没有 CLR -> C# 翻译。
    【解决方案2】:

    Type.FullName 就是你要找的东西。

    【讨论】:

    • 不,那将是一个非常不同的字符串 - 类似于:My.Code.Here.Class1`1+Enum1
    【解决方案3】:

    此代码应该适用于嵌套的泛型类型(例如Foo&lt;int&gt;.Bar&lt;string,object&gt;)。

    public static string GetCSharpTypeName(this Type type, bool getFullName)
    {
        StringBuilder sb = new StringBuilder();
        if (getFullName && !string.IsNullOrEmpty(type.Namespace))
        {
            sb.Append(type.Namespace);
            sb.Append(".");
        }
        AppendCSharpTypeName(sb, type, getFullName);
        return sb.ToString();
    }
    
    private static void AppendCSharpTypeName
        (StringBuilder sb, Type type, bool fullParameterNames)
    {
        string typeName = type.Name;
        Type declaringType = type.DeclaringType;
    
        int declaringTypeArgumentCount = 0;
        if (type.IsNested)
        {
            if (declaringType.IsGenericTypeDefinition)
            {
                declaringTypeArgumentCount = 
                    declaringType.GetGenericArguments().Length;
                declaringType = declaringType.MakeGenericType(
                    type.GetGenericArguments().Take(declaringTypeArgumentCount)
                        .ToArray());
            }
    
            AppendCSharpTypeName(sb, declaringType, fullParameterNames);
            sb.Append(".");
        }
        Type[] genericArguments = type.GetGenericArguments()
            .Skip(declaringTypeArgumentCount).ToArray();
    
        int stopIndex;
        if ((type.IsGenericTypeDefinition || type.IsGenericType)
            && ((stopIndex = type.Name.IndexOf('`')) > 0))
        {
            sb.Append(typeName.Substring(0, stopIndex));
            string[] genericArgumentNames = genericArguments
                .Select(t => GetCSharpTypeName(t, fullParameterNames)).ToArray();
            if (genericArgumentNames.Length > 0)
                sb.AppendFormat("<{0}>", string.Join(",", genericArgumentNames));
        }
        else
        {
            sb.Append(typeName);
        }
    }
    

    【讨论】:

      【解决方案4】:

      你的意思是你想要typeof(Class1&lt;&gt;.Enum1).FullName之类的东西吗?

      请注意,尽管正如 Marc 所指出的,如果您需要的正是您指定的格式,这给您的名称可能不是您想要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-04
        • 1970-01-01
        • 1970-01-01
        • 2016-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多