web-dev-qa-db-ja.com

文字列表現からジェネリック型を取得するにはどうすればよいですか?

私は持っています MyClass<T>

そして、私はこれを持っていますstring s = "MyClass<AnotherClass>";。文字列sからTypeを取得するにはどうすればよいですか?

1つの方法(ugい)は、「<」と「>」を解析して実行することです。

Type acType = Type.GetType("AnotherClass");  
Type whatIwant = typeof (MyClass<>).MakeGenericType(acType);

しかし、解析などせずに最終型を取得するためのよりクリーンな方法はありますか?

78

genericsの形式 は、名前、 `文字、型パラメーターの数、それに続く括弧内の型のコンマ区切りリストです。

Type.GetType("System.Collections.Generic.IEnumerable`1[System.String]");

ジェネリックのC#構文からCLRが必要とする種類の文字列に変換する簡単な方法があるかどうかはわかりません。あなたが質問で言及したようにそれを解析するために簡単な正規表現を書き始めましたが、型パラメータとしてネストされたジェネリックを持つ能力を放棄しない限り、解析は非常に複雑になることに気付きました。

93
Neil Williams

_Activator.CreateInstance_を確認してください-型で呼び出すことができます

_Activator.CreateInstance(typeof(MyType))
_

または、アセンブリを使用し、名前をstringとして入力します

_Activator.CreateInstance("myAssembly", "myType")
_

これにより、必要なタイプのインスタンスが提供されます。

インスタンスではなくTypeが必要な場合は、Type.GetType()メソッドと興味のある型の完全修飾名を使用します。例:

_string s = "System.Text.StringBuilder";
Type myClassType = Type.GetType(s);
_

問題のTypeが表示されます。

38
marc_s

このようなものが必要だったので、必要な単純な型名を解析するためのコードを書くことになりました。もちろん、List<string>のような一般的な型名を識別しないため、改善の余地がありますが、stringint[]decimal?などの場合は問題ありません。これが誰にも役立つ場合の共有。

public static class TypeExtensions
{
  public static Type GetTypeFromSimpleName(string typeName)
  {
    if (typeName == null)
      throw new ArgumentNullException("typeName");

    bool isArray = false, isNullable = false;

    if (typeName.IndexOf("[]") != -1)
    {
      isArray = true;
      typeName = typeName.Remove(typeName.IndexOf("[]"), 2);
    }

    if (typeName.IndexOf("?") != -1)
    {
      isNullable = true;
      typeName = typeName.Remove(typeName.IndexOf("?"), 1);
    }

    typeName = typeName.ToLower();

    string parsedTypeName = null;
    switch (typeName)
    {
      case "bool":
      case "boolean":
        parsedTypeName = "System.Boolean";
        break;
      case "byte":
        parsedTypeName = "System.Byte";
        break;
      case "char":
        parsedTypeName = "System.Char";
        break;
      case "datetime":
        parsedTypeName = "System.DateTime";
        break;
      case "datetimeoffset":
        parsedTypeName = "System.DateTimeOffset";
        break;
      case "decimal":
        parsedTypeName = "System.Decimal";
        break;
      case "double":
        parsedTypeName = "System.Double";
        break;
      case "float":
        parsedTypeName = "System.Single";
        break;
      case "int16":
      case "short":
        parsedTypeName = "System.Int16";
        break;
      case "int32":
      case "int":
        parsedTypeName = "System.Int32";
        break;
      case "int64":
      case "long":
        parsedTypeName = "System.Int64";
        break;
      case "object":
        parsedTypeName = "System.Object";
        break;
      case "sbyte":
        parsedTypeName = "System.SByte";
        break;
      case "string":
        parsedTypeName = "System.String";
        break;
      case "timespan":
        parsedTypeName = "System.TimeSpan";
        break;
      case "uint16":
      case "ushort":
        parsedTypeName = "System.UInt16";
        break;
      case "uint32":
      case "uint":
        parsedTypeName = "System.UInt32";
        break;
      case "uint64":
      case "ulong":
        parsedTypeName = "System.UInt64";
        break;
    }

    if (parsedTypeName != null)
    {
      if (isArray)
        parsedTypeName = parsedTypeName + "[]";

      if (isNullable)
        parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]");
    }
    else
      parsedTypeName = typeName;

    // Expected to throw an exception in case the type has not been recognized.
    return Type.GetType(parsedTypeName);
  }
}

これを使うのは、これを書くのと同じくらい簡単です:

Type t;

t = TypeExtensions.GetTypeFromSimpleName("string");
t = TypeExtensions.GetTypeFromSimpleName("int[]");
t = TypeExtensions.GetTypeFromSimpleName("decimal?");
26

文字列から型オブジェクトを取得するには、次を使用します。

_Type mytype = Type.GetType(typeName);
_

これをActivator.CreateInstance()に渡すことができます:

_Activator.CreateInstance(mytype);
_
3
Turnor

これを解析する時間はあまりありませんが、似たような答えを見たことがあります。特に、彼らはあなたがここでやりたいことを正確にやっていると思う:

Entity Framework Generic Repository Error

(String.Format("[{0}]", baseType.Name.ToString())).OfType<T>();

これが役に立てば幸いです。そうでない場合は、より具体的にお知らせください。

0
Jeff Ancel