C# 在设计时使用全名查找类的类型
编辑:我正在使用该方法在Visual Studio的设计期间显示数据源配置向导。若用户选择一个对象(),并单击finish,我将得到一个字符串,如C# 在设计时使用全名查找类的类型,c#,.net,winforms,visual-studio,windows-forms-designer,C#,.net,Winforms,Visual Studio,Windows Forms Designer,编辑:我正在使用该方法在Visual Studio的设计期间显示数据源配置向导。若用户选择一个对象(),并单击finish,我将得到一个字符串,如“Namespace.ClassName”。要在designer中显示所选对象的属性,我需要以优化的方式找到对象的正确类型 我有一个类的名称及其命名空间(Application.Data.Employee)。我想找到包含此信息的类(雇员)的类型。目前,我正在使用以下代码查找类型 string classNameWithNameSpace = "Appl
“Namespace.ClassName”
。要在designer中显示所选对象的属性,我需要以优化的方式找到对象的正确类型
我有一个类的名称及其命名空间(Application.Data.Employee
)。我想找到包含此信息的类(雇员)的类型。目前,我正在使用以下代码查找类型
string classNameWithNameSpace = "Application.Data.Employee";
Type target;
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
foreach (Type t in assembly.GetTypes())
{
if (t.FullName.Equals(classNameWithNameSpace))
{
target = t;
break;
}
}
注意:程序集可能存在于项目中引用的任何dll中。我的代码还支持.Net Framework 2.0
我知道这不是最好的方法,原因如下
1) 两个或多个程序集可能具有相同的命名空间名称和类名
2) 我看到一个SO帖子声明,它将为动态程序集抛出NotSupportedException
3) 调试时,发现循环中检查了不需要或不必要程序集中的类型
AppDomain.CurrentDomain.GetAssemblys()
方法在设计时调试期间在一个简单项目中返回146个程序集
4) 如果上面的代码将一个不必要的程序集加载到内存中,它将出现在内存中,直到应用程序域出现为止(选中此链接中的卸载程序集部分)
有没有推荐的方法或最好的方法来做同样的事情 内部循环相当于调用
assembly.GetType(classNameWithNameSpace)
,因此您可以完全跳过它。这应该考虑到您列表中的第3项
可以通过确保程序集
在.NET 4.0中没有IsDynamic
标志或检查4.0之前的命名空间来解决第2项
此代码适用于.NET 2.0
IList<Type> matchingTypes = new List<Type>();
foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
// Skip dynamic assemblies.
if (a.GetType().StartsWith("System.Reflection.Emit.")) {
continue;
}
Type t = a.GetType(classNameWithNameSpace);
if (t != null) {
matchingTypes.Add(t);
}
}
上面给出了classNameWithNameSpace
的所有类型的列表
处理第#1项最好留给您的应用程序处理。您需要决定如何处理matchingTypes
列表中的每个类型
记住这一点很有用。上面的列表将包括这两种类型。您可以使用来决定实际应采用哪种类型。正如您所说,算法中的搜索也在扫描不需要的程序集。如果您计划只搜索您自己产品的组件,那么您可以利用组件的标准命名法,以备不时之需。这将大大减少扫描目标类型的目标程序集。第#XYZ行执行筛选相关程序集的初始任务,假设所有要搜索的程序集的名称中都有某个标准前缀
MyCompanyName.MyProductName
。另外,我已经用LINQ调用替换了您的大多数调用,这些调用在语法上更加干净
string classNameWithNameSpace = "Application.Data.Employee";
Type target;
var assemblyList = AppDomain.CurrentDomain.GetAssemblies();
//line # XYZ
var filteredAssembliesOfMyProduct =
assemblyList.Where(x => x.FullName.StartsWith("MyCompanyName.MyProductName"));
foreach (Assembly assembly in filteredAssembliesOfMyProduct)
if (assembly.GetTypes().Any(x => x.FullName == classNameWithNameSpace))
{
target = assembly.GetTypes().First(x => x.FullName == classNameWithNameSpace);
break;
}
您可以使用这些服务在设计时处理类型:
- 帮助您在设计时按名称检索程序集或类型
- 帮助您在设计时获取可用类型的列表
IServiceProvider
,它可以获得这些服务:
Type GetTypeByName(IServiceProvider provider, string typeName)
{
var svc= (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
return svc.GetType(typeName);
}
private List<Type> GetAllTypes(IServiceProvider provider)
{
var svc= (ITypeDiscoveryService)provider.GetService(typeof(ITypeDiscoveryService));
return svc.GetTypes(typeof(object), true).Cast<Type>().ToList();
}
Type.GetType(…)
?也许会有帮助,也许also@MongZhu,我的代码也会这样做,但这些都不是解决这个问题的最佳或好方法。顺便说一句,如果两个完全限定类型名完全相同的类存在于两个单独的程序集中,那么它们在实际编程场景中会有什么用呢。如果您在文件中引用两个程序集,编译器将永远无法区分它们program@RBT,在windows窗体中,数据源向导可在设计器中用于数据绑定。使用此选项,我们可以在设计期间选择任何类型作为数据源。我将其用于我的控件,向导将返回一个带有名称空间和类名的字符串。在设计期间,我需要从字符串中识别正确的类型TimeInQ受3.5框架的支持,IsDynamic受框架4的支持。我也需要支持2.0框架。所以我在我的code@Anand您可能想在您的帖子中提到这一点:我不知道您必须支持.NET 2.0。第3项是为了避免搜索不必要的程序集,而不是内部for循环。设计时有100多个程序集如果可以检查程序集中是否存在命名空间,我们可以避免不必要的搜索。由于名称空间的数量与类型相比非常少,所以问题是数据源向导显示所有可能程序集的类名。数据源向导属于VS,所以我也应该搜索系统程序集。如果控件的用户添加太多assembliesAppDomain,我可以看到我的代码会花费很长时间。CurrentDomain.GetAssemblys()在调试期间在一个简单的项目中返回一个包含146个程序集的数组。谢谢,我将给出一个示例try@Kira结果如何,您能否确认解决方案是否有效?我可以在VisualStudio的designer中使用该代码,它工作正常。请耐心等待,看起来您已经编辑了代码。但我没有收到关于此事的通知。我会检查一下,很快告诉你
Type GetTypeByName(IServiceProvider provider, string typeName)
{
var svc= (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
return svc.GetType(typeName);
}
private List<Type> GetAllTypes(IServiceProvider provider)
{
var svc= (ITypeDiscoveryService)provider.GetService(typeof(ITypeDiscoveryService));
return svc.GetTypes(typeof(object), true).Cast<Type>().ToList();
}
var svc = ((DataSourceProviderService)Site.GetService(typeof(DataSourceProviderService)));
if (svc != null)
{
var result = svc.InvokeAddNewDataSource(this, FormStartPosition.CenterScreen);
if(result!=null && result.DataSources.Count>0)
{
var type = GetTypeByName(this.Site, result.DataSources[0].TypeName);
var properties = type.GetProperties().ToList();
MessageBox.Show(string.Join(",", properties.Select(x => x.Name)));
}
}