Soru Yansıma kullanarak genel bir türün doğru metin tanımını nasıl edinebilirim?


Kod oluşturma üzerinde çalışıyorum ve jeneriklerle bir takılmaya girdim. İşte bana sorunlara neden olan şeyin "basitleştirilmiş" bir versiyonu.

Dictionary<string, DateTime> dictionary = new Dictionary<string, DateTime>();
string text = dictionary.GetType().FullName;

Yukarıdaki kod snippet'i ile değeri text Şöyleki:

 System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, 
 Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, 
 Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

(Daha iyi okunabilirlik için satır sonları eklendi.)

Tip adını almanın bir yolu var mıtypeYukarıdaki dizgeyi ayrıştırmadan farklı bir biçimde? İçin aşağıdaki sonucu istiyorum text:

System.Collections.Generic.Dictionary<System.String, System.DateTime>

25
2017-12-30 22:13


Menşei


Kaldırırsanız unutmayın .FullName ve kullan .ToString() bunun yerine, "metni" alırsınız System.Collections.Generic.Dictionary`2[System.String,System.DateTime] hangisi daha okunaklı ve ne istediğinize yakın. - Jeppe Stig Nielsen


Cevaplar:


Bu temsili .Net Framework'de almak için yerleşik bir yol yoktur. Yani, onu düzeltmenin bir yolu olmadığı için. C # stili sözdiziminde temsil edilemeyen çok sayıda yapı vardır. Örneğin "<> foo", IL'de geçerli bir tür adıdır, ancak C # ile temsil edilemez.

Ancak, oldukça iyi bir çözüm arıyorsanız, oldukça hızlı bir şekilde uygulanabilir. Aşağıdaki çözüm çoğu durum için çalışacaktır. İşlemeyecek

  1. İç içe türler
  2. Yasa Dışı C # İsimler
  3. Diğer senaryoların birkaçı

Örnek:

public static string GetFriendlyTypeName(Type type) {
    if (type.IsGenericParameter)
    {
        return type.Name;
    }

    if (!type.IsGenericType)
    {
        return type.FullName;
    }

    var builder = new System.Text.StringBuilder();
    var name = type.Name;
    var index = name.IndexOf("`");
    builder.AppendFormat("{0}.{1}", type.Namespace, name.Substring(0, index));
    builder.Append('<');
    var first = true;
    foreach (var arg in type.GetGenericArguments())
    {
        if (!first)
        {
            builder.Append(',');
        }
        builder.Append(GetFriendlyTypeName(arg));
        first = false;
    }
    builder.Append('>');
    return builder.ToString();
}

28
2017-12-30 23:23



eğer bir şansınız varsa cevabınızı düzenleyin ve "static string GetFriendlyTypeName (Type type) {if (type.IsGenericParameter) {code type.Name;}" kodunu kod bloğuna ekleyin :) - Jamey McElveen
@Jamey, bitti. Bu aslında oldukça garip. Kod bloğu, sıralı liste ile bloğun başlangıcı arasında kod olmayan bir satır ekleyene kadar ilk satırı eklemez. - JaredPar
ve üstüne ekleyin: bool bArray = false; if (type.IsArray) {bArray = true; type = type.GetElementType (); } ve altta ise (bArray) builder.Append ("[]"); builder.ToString (); dizileri desteklemek için. - Wolf5
Nullables'i ele almak isteyebilirsiniz ve virgülden sonra bir boşluk eklemek isteyebilirsiniz. - SLaks
ilk tür "if (type.IsGenericParameter) {...}" iyi bir fikir olmayabilir, çünkü jenerik tip parametresi genel bir türün kendisi olabilir. - Johnny5


İyi ve temiz bir alternatif, sayesinde @ LukeH kullanıcısının yorumu,

using System;
using System.CodeDom;
using System.Collections.Generic;
using Microsoft.CSharp;
//...
private string GetFriendlyTypeName(Type type)
{
    using (var p = new CSharpCodeProvider())
    {
        var r = new CodeTypeReference(type);
        return p.GetTypeOutput(r);
    }
}

19
2017-07-06 06:54



daha sonra cevap olarak işaretlenir (genel sınıfların alt sınıfları doğru şekilde gösterilir) - FLCL
Bunun herhangi bir performans etkisi var mı? - Robert Jeppesen


Bu akşam, uzatma yöntemleriyle biraz oynuyordum ve sorunuza bir cevap bulmaya çalıştım. İşte sonuç: bu bir garanti dışı kod. ;-)

internal static class TypeHelper
{
    private const char genericSpecialChar = '`';
    private const string genericSeparator = ", ";

    public static string GetCleanName(this Type t)
    {
        string name = t.Name;
        if (t.IsGenericType)
        {
            name = name.Remove(name.IndexOf(genericSpecialChar));
        }
        return name;
    }

    public static string GetCodeDefinition(this Type t)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("{0}.{1}", t.Namespace, t.GetCleanName());
        if (t.IsGenericType)
        {
            var names = from ga in t.GetGenericArguments()
                        select GetCodeDefinition(ga);
            sb.Append("<");
            sb.Append(string.Join(genericSeparator, names.ToArray()));
            sb.Append(">");
        }
        return sb.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        object[] testCases = { 
                                new Dictionary<string, DateTime>(),
                                new List<int>(),
                                new List<List<int>>(),
                                0
                            };
        Type t = testCases[0].GetType();
        string text = t.GetCodeDefinition();
        Console.WriteLine(text);
    }
}

4
2017-12-30 23:50





string text = dictionary.ToString();

Neredeyse ne istediğini sağlar:

System.Collections.Generic.Dictionary`2[System.String,System.DateTime]

2
2017-12-30 23:10



Ancak bu genel bir çözüm değildir. .ToString () kullanan herhangi bir tür bu çözümü kırar - JaredPar
@JaredPar Bu kullanarak çözüldü dictionary.GetType().ToString() yerine. - Jeppe Stig Nielsen


.NET'in bunu yapabilecek bir şeyleri olduğunu sanmıyorum, bunu kendiniz yapmak zorundasınız. Yansıma sınıflarının bu formdaki tür adını yeniden oluşturmak için yeterince bilgi sağladığını düşünüyorum.


0
2017-12-30 22:21



Bu yolu denedim, çözüm üzerinde ayrıntılı çalışabilir misiniz? Bildirimi yeniden oluşturmak için kullanabileceğim bu bilgiyi veren mülkleri veya koleksiyonları bulamadım. - Jamey McElveen


Geçebileceğine inanıyorum

System.String, mscorlib, Sürüm = 2.0.0.0, Kültür = tarafsız, PublicKeyToken = b77a5c561934e089

içine Type.Parse(). Bu tamamen nitelikli bir isim, bence.


0
2017-12-30 22:24



Gerekli değil. Orijinal Dictionary.GetType () öğesi zaten doğrudan erişebileceğiniz bir dizi parametre içerir. Aynı sonucu elde etmek için ayrışmaya gerek yok. - Vilx-