Câu hỏi Làm thế nào tôi có thể nhận được loại chung từ một đại diện chuỗi?


Tôi có MyClass<T>.

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

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

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

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


76
2018-04-06 15:03


gốc




Các câu trả lời:


Các định dạng cho generics là tên, một ký tự `, số tham số kiểu, theo sau là một danh sách được phân tách bằng dấu phẩy của các loại trong ngoặc vuông:

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

Tôi không chắc chắn có một cách dễ dàng để chuyển đổi từ cú pháp C # cho generics thành loại chuỗi mà CLR muốn. Tôi bắt đầu viết một regex nhanh để phân tích nó ra 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 generics như các tham số kiểu thì việc phân tích cú pháp sẽ rất phức tạp.


91
2018-04-06 15:36



1 - câu trả lời tuyệt vời, cảm ơn! Tôi đã không quan tâm xung quanh cố gắng tìm hiểu làm thế nào để xử lý Generics! - marc_s
Cảm ơn. Điều này làm việc và tôi phải sửa đổi mã để định dạng chuỗi theo cách này. Tuy nhiên, đã tự hỏi nếu vẫn còn một cách để chỉ đơn giản là sử dụng: "MyClass <AnotherClass>" chính xác cách nó được hiển thị trong chuỗi để có được thể loại Type. Có vẻ sạch hơn rất nhiều. - DeeStackOverflow
Bạn không cần 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


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

Activator.CreateInstance(typeof(MyType))

hoặc với một tên lắp ráp và loại như 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 Type thay vì ví dụ, sử dụng Type.GetType() và tên đầy đủ của loại 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 Type trong câu hỏi.


38
2018-04-06 15:06



Điều này chỉ nhận được một thể hiện của các loại, không phải là một thể hiện System.Type, mà dựa trên đoạn mã, có vẻ là những gì OP đang tìm kiếm. - Daniel Schaffer


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

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ó cũng đơn giản như viết này:

Type t;

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

26
2018-02-09 14:00



Đây là một đoạn mã hữu ích đáng kinh ngạc. - The Communist Duck
Ngắn, hoàn hảo, cực kỳ hữu ích! Cảm ơn - xrnd


Để 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 thông tin này đến Activator.CreateInstance():

Activator.CreateInstance(mytype);

3
2018-04-06 15:12





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:

Lỗi lưu trữ chung của khung thực thể

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

Hy vọng điều này sẽ giúp, hãy cho tôi biết cụ thể hơn nếu điều này không đúng.


0
2018-04-06 15:10