701 lines
28 KiB
C#
701 lines
28 KiB
C#
using NetDocsForLLM.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
|
|
namespace NetDocsForLLM.Services
|
|
{
|
|
public class XmlDocGenerator : IDocFxService
|
|
{
|
|
private readonly string _workingDirectory;
|
|
|
|
public XmlDocGenerator()
|
|
{
|
|
// Crear un directorio temporal para trabajar
|
|
_workingDirectory = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + Guid.NewGuid().ToString("N"));
|
|
Directory.CreateDirectory(_workingDirectory);
|
|
|
|
AppLogger.LogInfo($"Directorio de trabajo creado: {_workingDirectory}");
|
|
}
|
|
|
|
public async Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies)
|
|
{
|
|
// Crear directorio para metadatos
|
|
var metadataPath = Path.Combine(_workingDirectory, "metadata");
|
|
Directory.CreateDirectory(metadataPath);
|
|
|
|
AppLogger.LogInfo($"Directorio de metadatos creado: {metadataPath}");
|
|
AppLogger.LogInfo($"Iniciando análisis en {DateTime.Now}");
|
|
AppLogger.LogInfo($"Ensamblados a procesar: {assemblies.Count()}");
|
|
|
|
// Para cada ensamblado, generar documentación XML
|
|
foreach (var assembly in assemblies)
|
|
{
|
|
await Task.Run(() => GenerateXmlDocumentation(assembly, metadataPath));
|
|
}
|
|
|
|
return metadataPath;
|
|
}
|
|
|
|
private void GenerateXmlDocumentation(AssemblyModel assemblyModel, string outputPath)
|
|
{
|
|
try
|
|
{
|
|
Assembly assembly = assemblyModel.LoadedAssembly;
|
|
if (assembly == null)
|
|
{
|
|
AppLogger.LogError($"ERROR: El ensamblado {assemblyModel.Name} no está cargado");
|
|
return;
|
|
}
|
|
|
|
AppLogger.LogInfo($"\n=== Procesando ensamblado: {assemblyModel.Name} ===");
|
|
AppLogger.LogInfo($"Ruta: {assemblyModel.FilePath}");
|
|
AppLogger.LogInfo($"Versión: {assemblyModel.Version}");
|
|
|
|
// Crear el documento XML
|
|
XDocument doc = new XDocument(
|
|
new XDeclaration("1.0", "utf-8", null),
|
|
new XElement("doc",
|
|
new XElement("assembly",
|
|
new XElement("name", assembly.GetName().Name)
|
|
),
|
|
new XElement("members")
|
|
)
|
|
);
|
|
|
|
// Obtener el elemento members para agregar miembros
|
|
var membersElement = doc.Root.Element("members");
|
|
|
|
// Cargar documentación XML existente si hay
|
|
XDocument existingXmlDoc = null;
|
|
if (assemblyModel.HasXmlDocumentation && File.Exists(assemblyModel.XmlDocPath))
|
|
{
|
|
try
|
|
{
|
|
existingXmlDoc = XDocument.Load(assemblyModel.XmlDocPath);
|
|
AppLogger.LogInfo($"Documentación XML cargada: {assemblyModel.XmlDocPath}");
|
|
|
|
// Mostrar estadísticas del XML existente
|
|
var memberNodes = existingXmlDoc.Descendants("member").ToList();
|
|
AppLogger.LogInfo($"Entradas en XML existente: {memberNodes.Count}");
|
|
|
|
// Log de los primeros miembros para depuración
|
|
foreach (var node in memberNodes.Take(5))
|
|
{
|
|
string id = node.Attribute("name")?.Value;
|
|
AppLogger.LogDebug($" Miembro XML: {id}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogWarning($"Error al cargar XML: {ex.Message}");
|
|
existingXmlDoc = null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AppLogger.LogWarning("No se encontró documentación XML para este ensamblado");
|
|
}
|
|
|
|
// Procesar todos los tipos exportados
|
|
var exportedTypes = assembly.GetExportedTypes().ToList();
|
|
AppLogger.LogInfo($"Tipos exportados encontrados: {exportedTypes.Count}");
|
|
|
|
// Procesar todos los tipos exportados
|
|
int typesWithMembers = 0;
|
|
int typesWithoutMembers = 0;
|
|
int totalMethods = 0;
|
|
int totalProperties = 0;
|
|
int totalEvents = 0;
|
|
int totalFields = 0;
|
|
|
|
foreach (var type in exportedTypes)
|
|
{
|
|
try
|
|
{
|
|
AppLogger.IncrementTypeCount();
|
|
AppLogger.LogDebug($"Procesando tipo: {type.FullName}");
|
|
|
|
// Generar documentación para el tipo
|
|
bool hasMembers = GenerateTypeDocumentation(type, membersElement, existingXmlDoc);
|
|
|
|
if (hasMembers)
|
|
{
|
|
typesWithMembers++;
|
|
}
|
|
else
|
|
{
|
|
typesWithoutMembers++;
|
|
AppLogger.LogWarning($"⚠️ No se encontraron miembros para el tipo: {type.FullName}");
|
|
}
|
|
|
|
// Contar miembros por tipo para estadísticas
|
|
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
|
|
.Where(m => !m.IsSpecialName).ToList();
|
|
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
|
var events = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
|
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
|
|
|
totalMethods += methods.Count;
|
|
totalProperties += properties.Count;
|
|
totalEvents += events.Count;
|
|
totalFields += fields.Count;
|
|
|
|
AppLogger.LogDebug($" Miembros del tipo {type.Name}: Métodos={methods.Count}, Propiedades={properties.Count}, Eventos={events.Count}, Campos={fields.Count}");
|
|
|
|
// Generar entradas XML para los miembros
|
|
if (methods.Count > 0)
|
|
{
|
|
foreach (var method in methods)
|
|
{
|
|
AppLogger.IncrementMemberCount();
|
|
GenerateMethodDocumentation(method, membersElement, existingXmlDoc);
|
|
}
|
|
}
|
|
|
|
if (properties.Count > 0)
|
|
{
|
|
foreach (var property in properties)
|
|
{
|
|
AppLogger.IncrementMemberCount();
|
|
GeneratePropertyDocumentation(property, membersElement, existingXmlDoc);
|
|
}
|
|
}
|
|
|
|
if (events.Count > 0)
|
|
{
|
|
foreach (var eventInfo in events)
|
|
{
|
|
AppLogger.IncrementMemberCount();
|
|
GenerateEventDocumentation(eventInfo, membersElement, existingXmlDoc);
|
|
}
|
|
}
|
|
|
|
if (fields.Count > 0)
|
|
{
|
|
foreach (var field in fields)
|
|
{
|
|
AppLogger.IncrementMemberCount();
|
|
GenerateFieldDocumentation(field, membersElement, existingXmlDoc);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error procesando tipo {type.FullName}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
// Estadísticas finales
|
|
AppLogger.LogInfo($"Estadísticas de procesamiento para {assemblyModel.Name}:");
|
|
AppLogger.LogInfo($" Tipos totales: {exportedTypes.Count}");
|
|
AppLogger.LogInfo($" Tipos con miembros: {typesWithMembers}");
|
|
AppLogger.LogInfo($" Tipos sin miembros: {typesWithoutMembers}");
|
|
AppLogger.LogInfo($" Total de métodos: {totalMethods}");
|
|
AppLogger.LogInfo($" Total de propiedades: {totalProperties}");
|
|
AppLogger.LogInfo($" Total de eventos: {totalEvents}");
|
|
AppLogger.LogInfo($" Total de campos: {totalFields}");
|
|
|
|
// Guardar la documentación XML generada
|
|
string xmlFileName = $"{assembly.GetName().Name}_generated.xml";
|
|
string xmlFilePath = Path.Combine(outputPath, xmlFileName);
|
|
|
|
// Guardar con formato
|
|
using (var writer = new XmlTextWriter(xmlFilePath, Encoding.UTF8))
|
|
{
|
|
writer.Formatting = System.Xml.Formatting.Indented;
|
|
writer.Indentation = 4;
|
|
doc.Save(writer);
|
|
}
|
|
|
|
AppLogger.LogInfo($"Documentación XML guardada en: {xmlFilePath}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"ERROR general procesando ensamblado {assemblyModel.Name}: {ex.Message}");
|
|
AppLogger.LogError(ex.StackTrace);
|
|
}
|
|
}
|
|
|
|
private bool GenerateTypeDocumentation(Type type, XElement membersElement, XDocument existingXmlDoc)
|
|
{
|
|
string typeId = $"T:{type.FullName}";
|
|
|
|
// Intentar encontrar documentación existente
|
|
string summary = null;
|
|
string remarks = null;
|
|
|
|
if (existingXmlDoc != null)
|
|
{
|
|
var existingMember = existingXmlDoc.Descendants("member")
|
|
.FirstOrDefault(m => m.Attribute("name")?.Value == typeId);
|
|
|
|
if (existingMember != null)
|
|
{
|
|
AppLogger.LogDebug($" Encontrada documentación XML existente para {typeId}");
|
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
|
remarks = existingMember.Element("remarks")?.Value?.Trim();
|
|
}
|
|
}
|
|
|
|
// Si no hay documentación existente, generar una descripción genérica
|
|
if (string.IsNullOrEmpty(summary))
|
|
{
|
|
summary = $"Represents a {GetTypeKindDescription(type)}: {type.Name}";
|
|
}
|
|
|
|
var memberElement = new XElement("member", new XAttribute("name", typeId));
|
|
memberElement.Add(new XElement("summary", summary));
|
|
|
|
// Agregar observaciones si están disponibles o generarlas
|
|
if (!string.IsNullOrEmpty(remarks))
|
|
{
|
|
memberElement.Add(new XElement("remarks", remarks));
|
|
}
|
|
else
|
|
{
|
|
var remarksBuilder = new StringBuilder();
|
|
|
|
// Si es una clase que hereda de otra (excepto Object), agregar esa información
|
|
if (type.IsClass && type.BaseType != null && type.BaseType != typeof(object))
|
|
{
|
|
remarksBuilder.AppendLine($"Inherits from {type.BaseType.Name}");
|
|
}
|
|
|
|
// Si implementa interfaces, mencionarlas
|
|
var interfaces = type.GetInterfaces();
|
|
if (interfaces.Length > 0)
|
|
{
|
|
if (remarksBuilder.Length > 0)
|
|
remarksBuilder.AppendLine();
|
|
|
|
remarksBuilder.Append($"Implements: {string.Join(", ", interfaces.Select(i => i.Name))}");
|
|
}
|
|
|
|
if (remarksBuilder.Length > 0)
|
|
{
|
|
memberElement.Add(new XElement("remarks", remarksBuilder.ToString()));
|
|
}
|
|
}
|
|
|
|
membersElement.Add(memberElement);
|
|
|
|
// Verificar si el tipo tiene miembros
|
|
bool hasMembers =
|
|
type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any(m => !m.IsSpecialName) ||
|
|
type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any() ||
|
|
type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any() ||
|
|
type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any();
|
|
|
|
return hasMembers;
|
|
}
|
|
|
|
private void GenerateMethodDocumentation(MethodInfo method, XElement membersElement, XDocument existingXmlDoc)
|
|
{
|
|
try
|
|
{
|
|
// Generar ID XML para el método
|
|
string methodId = GetMethodXmlId(method);
|
|
AppLogger.LogDebug($" Procesando método: {methodId}");
|
|
|
|
// Intentar encontrar documentación existente
|
|
string summary = null;
|
|
string returns = null;
|
|
Dictionary<string, string> paramDescriptions = new Dictionary<string, string>();
|
|
|
|
if (existingXmlDoc != null)
|
|
{
|
|
var existingMember = existingXmlDoc.Descendants("member")
|
|
.FirstOrDefault(m => m.Attribute("name")?.Value == methodId);
|
|
|
|
if (existingMember != null)
|
|
{
|
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
|
returns = existingMember.Element("returns")?.Value?.Trim();
|
|
|
|
foreach (var paramElement in existingMember.Elements("param"))
|
|
{
|
|
string paramName = paramElement.Attribute("name")?.Value;
|
|
string paramDesc = paramElement.Value?.Trim();
|
|
|
|
if (!string.IsNullOrEmpty(paramName) && !string.IsNullOrEmpty(paramDesc))
|
|
{
|
|
paramDescriptions[paramName] = paramDesc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Si no hay documentación existente, generar una descripción genérica
|
|
if (string.IsNullOrEmpty(summary))
|
|
{
|
|
summary = $"{method.Name} {GetMethodDescription(method)}";
|
|
}
|
|
|
|
var element = new XElement("member",
|
|
new XAttribute("name", methodId),
|
|
new XElement("summary", summary)
|
|
);
|
|
|
|
// Agregar parámetros
|
|
var parameters = method.GetParameters();
|
|
foreach (var param in parameters)
|
|
{
|
|
string paramDesc;
|
|
if (!paramDescriptions.TryGetValue(param.Name, out paramDesc))
|
|
{
|
|
paramDesc = GetParameterDescription(param);
|
|
}
|
|
|
|
element.Add(new XElement("param",
|
|
new XAttribute("name", param.Name),
|
|
new XText(paramDesc)
|
|
));
|
|
}
|
|
|
|
// Agregar información de retorno si no es void
|
|
if (method.ReturnType != typeof(void))
|
|
{
|
|
if (string.IsNullOrEmpty(returns))
|
|
{
|
|
returns = $"A {GetSimpleTypeName(method.ReturnType)} value.";
|
|
}
|
|
|
|
element.Add(new XElement("returns", returns));
|
|
}
|
|
|
|
membersElement.Add(element);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error generando documentación para método {method.Name}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void GeneratePropertyDocumentation(PropertyInfo property, XElement membersElement, XDocument existingXmlDoc)
|
|
{
|
|
try
|
|
{
|
|
string propertyId = $"P:{property.DeclaringType.FullName}.{property.Name}";
|
|
AppLogger.LogDebug($" Procesando propiedad: {propertyId}");
|
|
|
|
// Intentar encontrar documentación existente
|
|
string summary = null;
|
|
string value = null;
|
|
|
|
if (existingXmlDoc != null)
|
|
{
|
|
var existingMember = existingXmlDoc.Descendants("member")
|
|
.FirstOrDefault(m => m.Attribute("name")?.Value == propertyId);
|
|
|
|
if (existingMember != null)
|
|
{
|
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
|
value = existingMember.Element("value")?.Value?.Trim();
|
|
}
|
|
}
|
|
|
|
// Si no hay documentación existente, generar una descripción genérica
|
|
if (string.IsNullOrEmpty(summary))
|
|
{
|
|
summary = $"Gets{(property.CanWrite ? " or sets" : "")} the {property.Name} property.";
|
|
}
|
|
|
|
var element = new XElement("member",
|
|
new XAttribute("name", propertyId),
|
|
new XElement("summary", summary)
|
|
);
|
|
|
|
// Agregar descripción de valor si está disponible o generarla
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
value = $"A {GetSimpleTypeName(property.PropertyType)} representing the {property.Name}.";
|
|
}
|
|
|
|
element.Add(new XElement("value", value));
|
|
|
|
membersElement.Add(element);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error generando documentación para propiedad {property.Name}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void GenerateEventDocumentation(EventInfo eventInfo, XElement membersElement, XDocument existingXmlDoc)
|
|
{
|
|
try
|
|
{
|
|
string eventId = $"E:{eventInfo.DeclaringType.FullName}.{eventInfo.Name}";
|
|
AppLogger.LogDebug($" Procesando evento: {eventId}");
|
|
|
|
// Intentar encontrar documentación existente
|
|
string summary = null;
|
|
|
|
if (existingXmlDoc != null)
|
|
{
|
|
var existingMember = existingXmlDoc.Descendants("member")
|
|
.FirstOrDefault(m => m.Attribute("name")?.Value == eventId);
|
|
|
|
if (existingMember != null)
|
|
{
|
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
|
}
|
|
}
|
|
|
|
// Si no hay documentación existente, generar una descripción genérica
|
|
if (string.IsNullOrEmpty(summary))
|
|
{
|
|
summary = $"Occurs when {eventInfo.Name} is raised.";
|
|
}
|
|
|
|
var element = new XElement("member",
|
|
new XAttribute("name", eventId),
|
|
new XElement("summary", summary)
|
|
);
|
|
|
|
// Agregar remarks con el tipo del handler
|
|
element.Add(new XElement("remarks",
|
|
$"Event handler type: {GetSimpleTypeName(eventInfo.EventHandlerType)}"
|
|
));
|
|
|
|
membersElement.Add(element);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error generando documentación para evento {eventInfo.Name}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void GenerateFieldDocumentation(FieldInfo field, XElement membersElement, XDocument existingXmlDoc)
|
|
{
|
|
try
|
|
{
|
|
string fieldId = $"F:{field.DeclaringType.FullName}.{field.Name}";
|
|
AppLogger.LogDebug($" Procesando campo: {fieldId}");
|
|
|
|
// Intentar encontrar documentación existente
|
|
string summary = null;
|
|
|
|
if (existingXmlDoc != null)
|
|
{
|
|
var existingMember = existingXmlDoc.Descendants("member")
|
|
.FirstOrDefault(m => m.Attribute("name")?.Value == fieldId);
|
|
|
|
if (existingMember != null)
|
|
{
|
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
|
}
|
|
}
|
|
|
|
// Modificadores
|
|
string modifiers = "";
|
|
if (field.IsStatic) modifiers += "static ";
|
|
if (field.IsInitOnly) modifiers += "readonly ";
|
|
if (field.IsLiteral) modifiers += "constant ";
|
|
|
|
// Si no hay documentación existente, generar una descripción genérica
|
|
if (string.IsNullOrEmpty(summary))
|
|
{
|
|
summary = $"Represents the {modifiers}{field.Name} field.";
|
|
}
|
|
|
|
var element = new XElement("member",
|
|
new XAttribute("name", fieldId),
|
|
new XElement("summary", summary)
|
|
);
|
|
|
|
membersElement.Add(element);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error generando documentación para campo {field.Name}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
// Métodos auxiliares
|
|
|
|
private string GetMethodXmlId(MethodInfo method)
|
|
{
|
|
try
|
|
{
|
|
var parameters = method.GetParameters();
|
|
if (parameters.Length == 0)
|
|
{
|
|
return $"M:{method.DeclaringType.FullName}.{method.Name}";
|
|
}
|
|
|
|
var paramTypes = string.Join(",", parameters.Select(p => GetParameterTypeName(p.ParameterType)));
|
|
return $"M:{method.DeclaringType.FullName}.{method.Name}({paramTypes})";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogger.LogError($"Error generando XML ID para método {method.Name}: {ex.Message}");
|
|
return $"M:{method.DeclaringType.FullName}.{method.Name}";
|
|
}
|
|
}
|
|
|
|
private string GetParameterTypeName(Type type)
|
|
{
|
|
try
|
|
{
|
|
// El formato de los parámetros en los IDs XML de documentación es específico
|
|
|
|
// Arrays
|
|
if (type.IsArray)
|
|
{
|
|
return $"{GetParameterTypeName(type.GetElementType())}[]";
|
|
}
|
|
|
|
// Genéricos
|
|
if (type.IsGenericType)
|
|
{
|
|
var genericTypeDef = type.GetGenericTypeDefinition();
|
|
var genericArgs = string.Join(",", type.GetGenericArguments().Select(GetParameterTypeName));
|
|
|
|
// Para tipos como List<T>, devolver algo como System.Collections.Generic.List{T}
|
|
string baseTypeName;
|
|
if (genericTypeDef.FullName != null && genericTypeDef.FullName.Contains('`'))
|
|
{
|
|
baseTypeName = genericTypeDef.FullName.Split('`')[0];
|
|
}
|
|
else
|
|
{
|
|
baseTypeName = genericTypeDef.Namespace + "." + genericTypeDef.Name.Split('`')[0];
|
|
}
|
|
|
|
return $"{baseTypeName}{{{genericArgs}}}";
|
|
}
|
|
|
|
// Para tipos normales, usar el nombre completo
|
|
return type.FullName;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// En caso de error, devolver un nombre genérico
|
|
return "System.Object";
|
|
}
|
|
}
|
|
|
|
private string GetTypeKindDescription(Type type)
|
|
{
|
|
if (type.IsEnum) return "enumeration";
|
|
if (type.IsInterface) return "interface";
|
|
if (type.IsValueType && !type.IsPrimitive) return "structure";
|
|
if (type.IsClass)
|
|
{
|
|
if (type.IsAbstract && type.IsSealed) return "static class";
|
|
if (type.IsAbstract) return "abstract class";
|
|
return "class";
|
|
}
|
|
return "type";
|
|
}
|
|
|
|
private string GetMethodDescription(MethodInfo method)
|
|
{
|
|
// Crear una descripción básica basada en el nombre y parámetros
|
|
var parameters = method.GetParameters();
|
|
|
|
if (parameters.Length == 0)
|
|
{
|
|
if (method.ReturnType == typeof(void))
|
|
{
|
|
return "performs an operation.";
|
|
}
|
|
return $"returns a {GetSimpleTypeName(method.ReturnType)} value.";
|
|
}
|
|
|
|
return $"with {parameters.Length} parameter{(parameters.Length > 1 ? "s" : "")}.";
|
|
}
|
|
|
|
private string GetParameterDescription(ParameterInfo param)
|
|
{
|
|
string desc = $"A {GetSimpleTypeName(param.ParameterType)}";
|
|
|
|
if (param.IsOptional)
|
|
{
|
|
object defaultValue = param.DefaultValue;
|
|
string defaultValueStr = defaultValue?.ToString() ?? "null";
|
|
|
|
if (param.ParameterType == typeof(string) && defaultValue != null)
|
|
{
|
|
defaultValueStr = $"\"{defaultValueStr}\"";
|
|
}
|
|
|
|
desc += $" (Optional, defaults to {defaultValueStr})";
|
|
}
|
|
|
|
if (param.IsOut)
|
|
{
|
|
desc += " (Output)";
|
|
}
|
|
else if (param.ParameterType.IsByRef)
|
|
{
|
|
desc += " (Reference)";
|
|
}
|
|
|
|
return desc;
|
|
}
|
|
|
|
private string GetSimpleTypeName(Type type)
|
|
{
|
|
try
|
|
{
|
|
if (type == null) return "void";
|
|
|
|
// Si es un tipo por referencia (como out o ref parámetros)
|
|
if (type.IsByRef)
|
|
{
|
|
return GetSimpleTypeName(type.GetElementType());
|
|
}
|
|
|
|
// Tipos primitivos
|
|
if (type == typeof(void)) return "void";
|
|
if (type == typeof(int)) return "int";
|
|
if (type == typeof(string)) return "string";
|
|
if (type == typeof(bool)) return "bool";
|
|
if (type == typeof(double)) return "double";
|
|
if (type == typeof(float)) return "float";
|
|
if (type == typeof(decimal)) return "decimal";
|
|
if (type == typeof(object)) return "object";
|
|
|
|
// Arrays
|
|
if (type.IsArray)
|
|
{
|
|
return $"{GetSimpleTypeName(type.GetElementType())}[]";
|
|
}
|
|
|
|
// Genéricos
|
|
if (type.IsGenericType)
|
|
{
|
|
string baseName = type.Name;
|
|
int tickIndex = baseName.IndexOf('`');
|
|
if (tickIndex > 0)
|
|
{
|
|
baseName = baseName.Substring(0, tickIndex);
|
|
}
|
|
|
|
var argTypes = type.GetGenericArguments()
|
|
.Select(GetSimpleTypeName)
|
|
.ToArray();
|
|
|
|
return $"{baseName}<{string.Join(", ", argTypes)}>";
|
|
}
|
|
|
|
// Para tipos normales, usar solo el nombre simple
|
|
return type.Name;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// En caso de error, devolver un nombre genérico
|
|
return "object";
|
|
}
|
|
}
|
|
}
|
|
} |