2009-06-05 2 views
1

私は、Typeオブジェクトの完全なC#宣言を生成する関数を記述しようとしています。現在の方法では、Typeオブジェクトに対して非常に手作業で特定のロジックを実行します。Typeに対して完全なC#宣言を得るには?

この宣言を生成するために.NETにいくつかの方法が組み込まれていますか?一例として、

、このクラスを取る:

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

機能(getCSharpDecそれを呼び出すことができますが)(.Enum1>クラス1 <)typeof演算で呼び出されたとき、それは「My.Code.Hereを返します。 Class1 <> .Enum1 "となります。

答えて

5

ここでの問題のカップル...

  • C#とType名ネストされたタイプの異なっ
  • C#とType名の一般的な種類の異なっ

マイナー余談、Class1<>.Enum1 ISNがあります。閉じたタイプですが、問題ではありません...

これはかなり近づいた - それはまだしかし、タイプから外側のジェネリックを保持:

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; 
    } 
} 
+0

潜在的な特殊なケースがたくさんある素敵な例です。ちょっと注意すると、genArgsのforループはstring.Join( "、"、genArgs.Select(x => x.FullName))で置き換えることができます。速度に差がある場合は、Marcsコードが速いかもしれないが私は個人的には可読性のためにループの1つのライナーを好むでしょう –

+0

とそれらを機能的に同等にするためには、選択のためにGetCSharpTypeName(T)を使用してください.FullName –

+0

コードMarcのおかげで、あなたのコードは私の現在のコード私は、特定の複雑さ(または少なくとも外部関数)を含まない解決策を見つけることを望んでいました。 – NoizWaves

1

はあなたがtypeof(Class1<>.Enum1).FullNameような何かをしたいわけですか?

Marcが示すように、指定した形式が正確に必要な場合は、この名前が正確には表示されないことがあります。

1

Type.FullNameはあなたが探しているものです。

+0

いいえ、それは非常に異なる文字列になります。My.Code.Here.Class1'1 + Enum1 –

1

このコードは、ネストされたジェネリックタイプ(たとえばFoo<int>.Bar<string,object>)で機能するはずです。

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); 
    } 
} 
関連する問題