c# - tipos - ¿Cómo puedo obtener la definición de texto correcta de un tipo genérico utilizando la reflexión?
introduccion de tipos de textos (6)
Creo que puedes pasar
System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089
en Type.Parse()
. Ese es un nombre de tipo completamente calificado, creo.
Estoy trabajando en la generación de código y me encontré con un problema con los genéricos. Aquí hay una versión "simplificada" de lo que me está causando problemas.
Dictionary<string, DateTime> dictionary = new Dictionary<string, DateTime>();
string text = dictionary.GetType().FullName;
Con el fragmento de código anterior, el valor del text
es el siguiente:
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]]
(Se agregaron saltos de línea para una mejor legibilidad).
¿Hay alguna manera de obtener el tipo de nombre ( type
) en un formato diferente sin analizar la cadena anterior? Deseo el siguiente resultado para el text
:
System.Collections.Generic.Dictionary<System.String, System.DateTime>
Esta noche estaba jugando un poco con los métodos de extensión e intenté encontrar una respuesta para su pregunta. Este es el resultado: es un código sin garantía. ;-)
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);
}
}
No creo que .NET tenga nada incorporado que pueda hacer esto, así que tendrás que hacerlo tú mismo. Creo que las clases de reflexión proporcionan información suficiente para reconstruir el nombre del tipo en esta forma.
No hay una forma incorporada de obtener esta representación en .Net Framework. A saber, porque no hay forma de hacerlo correcto. Hay un buen número de construcciones que no son representables en la sintaxis de estilo C #. Por ejemplo, "<> foo" es un nombre de tipo válido en IL pero no se puede representar en C #.
Sin embargo, si está buscando una solución bastante buena, puede implementarla a mano con bastante rapidez. La siguiente solución funcionará para la mayoría de las situaciones. No manejará
- Tipos anidados
- Nombres ilegales de C #
- Pareja de otros escenarios
Ejemplo:
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();
}
Una buena y limpia alternativa, gracias al comentario de @ LukeH , es
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);
}
}
string text = dictionary.ToString();
proporciona casi lo que estás pidiendo:
System.Collections.Generic.Dictionary`2[System.String,System.DateTime]