Найти все ссылки / объявления объекта во время выполнения в c # |StructureMap - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть класс LanguagePopupMessage, который используется во всем приложении (и во внешних библиотеках).Если этот класс создан, он выбирает пространство имен, в котором он был создан, и добавляет суффикс, который должен быть уникальным.

Вопрос: Как получить все определения LanguagePopupMessage, включая параметр fieldname?

Я использую structuremap в моем приложении.Он также сканирует все библиотеки при запуске, так что, возможно, есть возможность автоматизировать его.101

using System;
using System.Diagnostics;

namespace ConsoleApp1
{
    /// <summary>
    /// Creates the namespace for a popup window and has an additional flag for the caption
    /// </summary>
    public class LanguagePopupMessage
    {
        public string Namespace { get; }
        public string Caption => $"{Namespace}Caption";

        public LanguagePopupMessage(string fieldName)
        {
            if(string.IsNullOrEmpty(fieldName))
                throw new ArgumentNullException(nameof(fieldName));
            if (_GetNamespace() is Type type)
            {
                Namespace = $"{type}.{fieldName}";
            }
            else
            {
                throw new InvalidOperationException("could not fetch the namespace");
            }
        }

        private Type _GetNamespace()
        {
            StackTrace st = new StackTrace();
            foreach (var sf in st.GetFrames())
            {
                var type = sf.GetMethod().DeclaringType;
                if (type != GetType())
                {
                    return type;
                }
            }
            return null;
        }

        public override string ToString()
        {
            return $"Namespace '{Namespace}' Caption '{Caption}'";
        }
    }

    class Program
    {
        //ConsoleApp1.Program.PopupMessage.ConfigNotLoaded
        //ConsoleApp1.Program.PopupMessage.ConfigNotLoadedCaption
        private static readonly LanguagePopupMessage _CONFIG_NOT_LOADED_POPUP_MESSAGE = new LanguagePopupMessage("ConfigNotLoaded");

        static void Main(string[] args)
        {
            Console.ReadKey();
        }
    }
}

namespace ConsoleApp1.Subfolder
{
    public class SubfolderClass
    {
        /// <summary>
        /// ConsoleApp1.Subfolder.SubfolderClass.FooMessage
        /// ConsoleApp1.Subfolder.SubfolderClass.FooMessageCaption
        /// </summary>
        public static readonly LanguagePopupMessage Message = new LanguagePopupMessage("FooMessage");
    }
}

1 Ответ

0 голосов
/ 20 февраля 2019

Я сделал кастом IRegistrationConvention - FindAllLanguagePopupMessages для structuremap.Во время выполнения новый container сканирует все библиотеки -> все Types, если есть какие-либо FieldInfo типа LanguagePopupMessage, и добавляет его в коллекцию.

Чтобы повысить производительность, я сделал Attribute - ContainsTranslationDefinition для фильтрации classes.

Исходный код

public class ContainsTranslationDefinition : Attribute
{ }
/// <summary>
/// Creates the namespace for a popup window and has an additional flag for the caption
/// </summary>
public class LanguagePopupMessage
{
    public string Namespace { get; }
    public string Caption => $"{Namespace}Caption";

    public LanguagePopupMessage(string fieldName)
    {
        if(string.IsNullOrEmpty(fieldName))
            throw new ArgumentNullException(nameof(fieldName));
        if (_GetNamespace() is Type type)
        {
            Namespace = $"{type}.{fieldName}";
        }
        else
        {
            throw new InvalidOperationException("could not fetch the namespace");
        }
    }

    private Type _GetNamespace()
    {
        StackTrace st = new StackTrace();
        foreach (var sf in st.GetFrames())
        {
            var type = sf.GetMethod().DeclaringType;
            if (type != GetType())
            {
                return type;
            }
        }
        return null;
    }

    public override string ToString()
    {
        return $"Namespace '{Namespace}' Caption '{Caption}'";
    }
}

/// <summary>
/// Add <see cref="LanguagePopupMessage"/> into the <see cref="Container.Model"/> type lifecycle
/// </summary>
public class FindAllLanguagePopupMessages : IRegistrationConvention
{
    private readonly ILifecycle _Lifecycle = new UniquePerRequestLifecycle();

    public void ScanTypes(TypeSet types, Registry registry)
    {
        List<LanguagePopupMessage> dec = new List<LanguagePopupMessage>();
        foreach (Type type in types.AllTypes())
        {
            if (!Attribute.IsDefined(type, typeof(ContainsTranslationDefinition)))
            {
                continue;
            }
            _FindConfigDeclarations(type, dec);
        }

        foreach (LanguagePopupMessage languagePopupMessage in dec)
        {
            Console.WriteLine($"{languagePopupMessage}");
        }
    }

    private static void _FindConfigDeclarations(Type type, List<LanguagePopupMessage> declarations)
    {
        var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);

        declarations.AddRange(fields
            .Where(info => info.IsInitOnly && typeof(LanguagePopupMessage).IsAssignableFrom(info.FieldType))
            .Select(info => (LanguagePopupMessage)info.GetValue(null)));

        // find all nested class types and run method recursively
        foreach (var nestedType in type.GetNestedTypes(BindingFlags.Public))
        {
            _FindConfigDeclarations(nestedType, declarations);
        }
    }

}
[ContainsTranslationDefinition]
public class TestClass
{
    private static readonly LanguagePopupMessage _CONFIG_1 = new LanguagePopupMessage("ConfigNotLoaded1");

    private static readonly LanguagePopupMessage _CONFIG_2 = new LanguagePopupMessage("ConfigNotLoaded2");
}

[ContainsTranslationDefinition]
public class Program
{
    //ConsoleApp1.Program.PopupMessage.ConfigNotLoaded
    //ConsoleApp1.Program.PopupMessage.ConfigNotLoadedCaption
    private static readonly LanguagePopupMessage _CONFIG_NOT_LOADED_POPUP_MESSAGE = new LanguagePopupMessage("ConfigNotLoaded3");


    static void Main(string[] args)
    {
        // Create container and tell where to look for depencies
        IContainer container = new Container(c => c.Scan(scanner =>
        {
            scanner.TheCallingAssembly();
            scanner.WithDefaultConventions();
            scanner.AssembliesFromApplicationBaseDirectory();
            scanner.With(new FindAllLanguagePopupMessages());
        }));

        Console.ReadKey();
    }
}

Предварительный просмотр

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...