¿Hay alguna manera de obtener todos los espacios de nombres asociados con una clase / tipo usando Reflection?

Por ejemplo, asumiendo que mi variable es:

var list = List<MyClass> 

Y mi clase se define como

public class MyClass
{
   property int32 MyNumber {get; set;}
}

Me gustaría poder obtener los siguientes espacios de nombres devueltos:

  • MyCompany.MyClass (ya que se usa mi MyClass)
  • System.Collections.Generic (ya que está siendo utilizado por List)
  • Sistema como int32 (ya que está siendo utilizado por MyNumber)

Gracias.

3
Thierry 12 jul. 2020 a las 06:39

1 respuesta

La mejor respuesta

Puede analizar el tipo mediante la reflexión.

Obtendrá muchos más resultados de los esperados debido al diseño del marco.

Espero no haber cometido demasiados errores.

La prueba

namespace ConsoleApp
{
  public class Program
  {
    static public void Main(string[] args)
    {
      var list = new List<MyClass>();
      var typeSearched = list.GetType();
      Console.WriteLine($"{typeSearched.Name} needs these namespaces:");
      foreach ( var item in typeSearched.GetUsingNamespaces().OrderBy(kvp => kvp.Key) )
      {
        string names = string.Join(Environment.NewLine + "    ",
                                   item.Value.Select(t => t.Name)
                                             .OrderBy(n => n));
        Console.WriteLine($"# {item.Key} for type(s):" + Environment.NewLine +
                          $"    {names}");
        Console.WriteLine();
    }
  }
  public class MyClass
  {
    public Int32 MyNumber {get; set;}
  }
}

La clase de ayudante de reflexión

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

namespace ConsoleApp
{
  static public class ReflexionHelper
  {
    // See below
  }
}

Métodos de herramientas

static public void AddNoDuplicates<T>(this IList<T> list, T value)
{
  if ( !list.Contains(value) ) list.Add(value);
}

static public void AddNoDuplicates<TKey, TValue>(this IDictionary<TKey, List<TValue>> list,
                                                 TKey key, TValue value)
{
  if ( key == null ) return;
  if ( !list.ContainsKey(key) )
    list.Add(key, new List<TValue>() { value });
  else
  if ( !list[key].Contains(value) )
    list[key].Add(value);
}

static public void AddRangeNoDuplicates<T>(this IList<T> list, IEnumerable<T> collection)
{
  foreach ( T value in collection )
    if ( !list.Contains(value) )
      list.Add(value);
}

El método para analizar el tipo

static public Dictionary<string, List<Type>> GetUsingNamespaces(this Type typeSearched)
{
  var result = new Dictionary<string, List<Type>>();
  result.AddNoDuplicates(typeSearched.Namespace, typeSearched);
  foreach ( Type type in typeSearched.GetMembersTypes() )
  {
    result.AddNoDuplicates(type.Namespace, type);
    foreach ( var implement in type.GetInterfaces() )
      result.AddNoDuplicates(implement.Namespace, implement);
    foreach ( var argument in type.GetGenericArguments() )
      result.AddNoDuplicates(argument.Namespace, argument);
  }
  return result;
}

El método para obtener todos los miembros de un tipo

static public List<Type> GetMembersTypes(this Type type)
{
  var flags = BindingFlags.Static
            | BindingFlags.Instance
            | BindingFlags.Public
            | BindingFlags.NonPublic;
  var result = new List<Type>();
  foreach ( var field in type.GetFields(flags) )
    result.AddNoDuplicates(field.FieldType);
  foreach ( var property in type.GetProperties(flags) )
    result.AddNoDuplicates(property.PropertyType);
  foreach ( var ev in type.GetEvents(flags) )
    result.AddNoDuplicates(ev.EventHandlerType);
  foreach ( var method in type.GetMethods(flags) )
  {
    result.AddNoDuplicates(method.ReturnType);
    foreach ( var a in method.GetParameters() )
      result.AddNoDuplicates(a.ParameterType);
  }
  foreach ( var constructor in type.GetConstructors() )
    foreach ( var param in constructor.GetParameters() )
      result.AddNoDuplicates(param.ParameterType);
  foreach ( var nested in type.GetNestedTypes(flags) )
    result.AddRangeNoDuplicates(GetMembersTypes(nested));
  return result;
}

Mejoras futuras

Analiza atributos y otras cosas olvidadas.

Salida de prueba corta

ConsoleApp
System
System.Collections
System.Collections.Generic
System.Collections.ObjectModel
System.Reflection
System.Runtime.InteropServices
System.Runtime.Serialization

Salida de prueba completa

# ConsoleApp for type(s):
    MyClass
    MyClass[]

# System for type(s):
    Action`1
    Array
    Boolean
    Comparison`1
    Converter`2
    ICloneable
    IComparable
    IComparable`1
    IComparable`1
    IComparable`1
    IConvertible
    IDisposable
    IEquatable`1
    IEquatable`1
    IEquatable`1
    IFormattable
    Int32
    Object
    Predicate`1
    String
    Type
    Void

# System.Collections for type(s):
    ICollection
    IEnumerable
    IEnumerator
    IList
    IStructuralComparable
    IStructuralEquatable

# System.Collections.Generic for type(s):
    Enumerator
    ICollection`1
    ICollection`1
    ICollection`1
    ICollection`1
    IComparer`1
    IEnumerable`1
    IEnumerable`1
    IEnumerable`1
    IEnumerable`1
    IEnumerable`1
    IEnumerator`1
    IEnumerator`1
    IList`1
    IList`1
    IList`1
    IList`1
    IReadOnlyCollection`1
    IReadOnlyCollection`1
    IReadOnlyCollection`1
    IReadOnlyCollection`1
    IReadOnlyList`1
    IReadOnlyList`1
    IReadOnlyList`1
    IReadOnlyList`1
    List`1
    List`1
    List`1
    List`1
    T
    T
    T[]
    TOutput

# System.Collections.ObjectModel for type(s):
    ReadOnlyCollection`1

# System.Reflection for type(s):
    ICustomAttributeProvider
    IReflect

# System.Runtime.InteropServices for type(s):
    _MemberInfo
    _Type

# System.Runtime.Serialization for type(s):
    ISerializable

Algunos nombres de tipos están duplicados, pero la instancia de Tipo es diferente ...

0
Olivier Rogier 12 jul. 2020 a las 14:05