Làm cách nào để lấy Kiểu chung từ biểu diễn chuỗi?


79

Tôi có MyClass<T>.

Và sau đó tôi có cái này string s = "MyClass<AnotherClass>";. Làm cách nào để lấy Loại từ chuỗi s?

Một cách (xấu) là phân tích cú pháp "<" và ">" và thực hiện:

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

Nhưng có cách nào rõ ràng hơn để lấy loại cuối cùng mà không cần phân tích cú pháp, v.v. không?

Câu trả lời:


94

Các định dạng cho Generics là tên, một 'nhân vật, số lượng các thông số chủng loại, theo sau là một danh sách dấu phẩy phân cách các loại trong ngoặc:

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

Tôi không chắc có một cách dễ dàng để chuyển đổi từ cú pháp C # cho generic sang loại chuỗi mà CLR muốn. Tôi đã bắt đầu viết một regex nhanh để phân tích cú pháp như bạn đã đề cập trong câu hỏi, nhưng nhận ra rằng trừ khi bạn từ bỏ khả năng có các generic lồng nhau làm tham số kiểu thì việc phân tích cú pháp sẽ rất phức tạp.


+1 - câu trả lời tuyệt vời, cảm ơn! Tôi đang loay hoay tìm cách xử lý generic!
marc_s

Cảm ơn. Điều này hoạt động và tôi phải sửa đổi mã để định dạng chuỗi theo cách này. Tuy nhiên, tôi đang tự hỏi liệu có còn cách nào để sử dụng đơn giản: "MyClass <A AnotherClass>" chính xác như cách nó được hiển thị trong chuỗi để lấy cá thể Type hay không. Trông sạch sẽ hơn rất nhiều.
DeeStackOverflow

Bạn không phải sửa đổi mã để định dạng chuỗi theo cách này, chỉ cần gọi ToString () trên Type.
Rush Frisby

38

Kiểm tra Activator.CreateInstance- bạn có thể gọi nó với một loại

Activator.CreateInstance(typeof(MyType))

hoặc với một cụm và tên loại là string

Activator.CreateInstance("myAssembly", "myType")

Điều này sẽ cung cấp cho bạn một ví dụ về loại bạn cần.

Nếu bạn cần phiên bản Typechứ không phải phiên bản, hãy sử dụng Type.GetType()phương thức và tên đủ điều kiện của loại mà bạn quan tâm, ví dụ:

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

Điều đó sẽ cung cấp cho bạn Typecâu hỏi.


3
Điều này chỉ nhận được một phiên bản của kiểu, không phải một phiên bản System.Type, dựa trên đoạn mã, dường như là thứ mà OP đang tìm kiếm.
Daniel Schaffer

26

Tôi cần một cái gì đó như thế này và tôi đã viết một số mã để phân tích cú pháp các tên loại đơn giản mà tôi cần. Tất nhiên có chỗ cho cải tiến, vì nó sẽ không xác định tên kiểu chung chung như List<string>, nhưng nó không chỉ tốt cho string, int[], decimal?và như vậy. Chia sẻ trong trường hợp điều này giúp bất cứ ai.

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);
  }
}

Sử dụng nó đơn giản như viết sau:

Type t;

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

1
Ngắn gọn, Hoàn hảo, Cực kỳ Hữu ích! Cảm ơn
xrnd

3

Để chỉ lấy đối tượng kiểu từ chuỗi, hãy sử dụng:

Type mytype = Type.GetType(typeName);

Sau đó, bạn có thể chuyển nó đến Activator.CreateInstance():

Activator.CreateInstance(mytype);

0

Tôi không có nhiều thời gian để phân tích điều này, mặc dù tôi nghĩ rằng tôi đã thấy một số câu trả lời tương tự. Đặc biệt, tôi nghĩ rằng họ đang làm chính xác những gì bạn muốn làm ở đây:

Entity Framework Generic Repository Error

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

Hy vọng rằng điều này sẽ hữu ích, hãy cho tôi biết cụ thể hơn nếu không.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.