反思——收集WinForm控件
Reflection - Collect WinForm Controls
DESCRIPTION:我想从许多程序集的 1000 多个 Winforms 中获取所有可用的控件。我不想进行大量的重构工作。 (小工具,内部使用原因)
已经完成的工作:获得了所有程序集,并且从每个程序集中通过 type.IsSubclassOf(selectedType)
.
获取了我感兴趣的所有类型
主要项目的信息:许多 classes 都有默认构造函数,有些没有,其他引用其他基础 classes。项目结构不是那么理想,因为它是一个开发超过 15 年的产品。
问题:我尝试使用 Activator.CreateInstance(type)
通过反射获取所有控制,但对于许多 classes 我采取了未处理的异常或其他基础class 无法管理的异常。在此过程中我面临的另一个问题是选角。我也试过 FormatterServices.GetUninitializedObject(type)
但我没有找到如何或是否可以控制。
问题: 是否可以不费吹灰之力收集具有这种结构的winForm 'Form' 控件?实现这一目标的不同方法是什么?
代码示例
static List<AssemblyName> _assemblyList=new List<AssemblyName>();
static List<Type> _typeList = new List<Type>();
static List<Control> _controlList = new List<Control>();
private static void getFormTypes()
{
foreach (AssemblyName assemblyName in _assemblyList)
{
Assembly assembly = Assembly.Load(assemblyName);
foreach (Type type in assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(Form)))
{
_typeList.Add(type);
}
}
}
}
private static void getAllControlsFromFormTypes()
{
foreach (Type type in _typeList)
{
object instance = default;
if (HasValidConstructor(type))
{
instance = Activator.CreateInstance(type);//Here I have unhandled exceptions from base classes during constructor invoking
GetValidControls((Control)instance);
}
}
}
private static void GetValidControls(Control container)
{
foreach (Control control in container.Controls)
{
GetValidControls(control);
if (!string.IsNullOrEmpty(control.Name) && !string.IsNullOrEmpty(control.Text))
{
_controlList.Add(control);
}
}
}
public static bool HasValidConstructor(Type t) => t.IsValueType || !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null;```
当您在表单中放置一个控件时,设计器会为该控件创建一个成员字段。如果您没有更改 GenerateMember
属性 来更改此行为,或者没有使用创建没有成员变量的标签的数据表单向导,那么您可以使用这些成员字段获取所有控件而无需实例化表格。
对于每个程序集,您无需通过这种方式实例化即可获得窗体和控件的列表:
IEnumerable<Type> GetFormsAndControlsTypes(Assembly assembly)
{
var forms = assembly.GetTypes()
.Where(type => typeof(Form).IsAssignableFrom(type));
var controls = forms.SelectMany(
form => form.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(field => typeof(Control).IsAssignableFrom(field.FieldType))
.Select(field => field.FieldType));
return forms.Concat(controls).Distinct().ToList();
}
但是,一般来说,这样的任务看起来像是代码分析,而不是 运行 时间任务。
DESCRIPTION:我想从许多程序集的 1000 多个 Winforms 中获取所有可用的控件。我不想进行大量的重构工作。 (小工具,内部使用原因)
已经完成的工作:获得了所有程序集,并且从每个程序集中通过 type.IsSubclassOf(selectedType)
.
主要项目的信息:许多 classes 都有默认构造函数,有些没有,其他引用其他基础 classes。项目结构不是那么理想,因为它是一个开发超过 15 年的产品。
问题:我尝试使用 Activator.CreateInstance(type)
通过反射获取所有控制,但对于许多 classes 我采取了未处理的异常或其他基础class 无法管理的异常。在此过程中我面临的另一个问题是选角。我也试过 FormatterServices.GetUninitializedObject(type)
但我没有找到如何或是否可以控制。
问题: 是否可以不费吹灰之力收集具有这种结构的winForm 'Form' 控件?实现这一目标的不同方法是什么?
代码示例
static List<AssemblyName> _assemblyList=new List<AssemblyName>();
static List<Type> _typeList = new List<Type>();
static List<Control> _controlList = new List<Control>();
private static void getFormTypes()
{
foreach (AssemblyName assemblyName in _assemblyList)
{
Assembly assembly = Assembly.Load(assemblyName);
foreach (Type type in assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(Form)))
{
_typeList.Add(type);
}
}
}
}
private static void getAllControlsFromFormTypes()
{
foreach (Type type in _typeList)
{
object instance = default;
if (HasValidConstructor(type))
{
instance = Activator.CreateInstance(type);//Here I have unhandled exceptions from base classes during constructor invoking
GetValidControls((Control)instance);
}
}
}
private static void GetValidControls(Control container)
{
foreach (Control control in container.Controls)
{
GetValidControls(control);
if (!string.IsNullOrEmpty(control.Name) && !string.IsNullOrEmpty(control.Text))
{
_controlList.Add(control);
}
}
}
public static bool HasValidConstructor(Type t) => t.IsValueType || !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null;```
当您在表单中放置一个控件时,设计器会为该控件创建一个成员字段。如果您没有更改 GenerateMember
属性 来更改此行为,或者没有使用创建没有成员变量的标签的数据表单向导,那么您可以使用这些成员字段获取所有控件而无需实例化表格。
对于每个程序集,您无需通过这种方式实例化即可获得窗体和控件的列表:
IEnumerable<Type> GetFormsAndControlsTypes(Assembly assembly)
{
var forms = assembly.GetTypes()
.Where(type => typeof(Form).IsAssignableFrom(type));
var controls = forms.SelectMany(
form => form.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(field => typeof(Control).IsAssignableFrom(field.FieldType))
.Select(field => field.FieldType));
return forms.Concat(controls).Distinct().ToList();
}
但是,一般来说,这样的任务看起来像是代码分析,而不是 运行 时间任务。