在 C# 中运行时查找对象的所有 references/declarations |结构图
Find all references/declarations of an object at runtime in c# | structuremap
我有一个 class LanguagePopupMessage
用于整个应用程序(和外部库)。如果构造此 class,它会获取创建它的命名空间并添加一个后缀以使其唯一。
问题是:如何获取所有 LanguagePopupMessage
定义,包括 fieldname
参数?
我在我的应用程序中使用 structuremap
。它也在启动时扫描所有库,所以也许有可能如何自动化它。
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");
}
}
我为 structuremap
定制了 IRegistrationConvention
- FindAllLanguagePopupMessages
。在运行时,一个新的 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();
}
}
预览
我有一个 class LanguagePopupMessage
用于整个应用程序(和外部库)。如果构造此 class,它会获取创建它的命名空间并添加一个后缀以使其唯一。
问题是:如何获取所有 LanguagePopupMessage
定义,包括 fieldname
参数?
我在我的应用程序中使用 structuremap
。它也在启动时扫描所有库,所以也许有可能如何自动化它。
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");
}
}
我为 structuremap
定制了 IRegistrationConvention
- FindAllLanguagePopupMessages
。在运行时,一个新的 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();
}
}