C# 在设计时使用全名查找类的类型

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

编辑:我正在使用该方法在Visual Studio的设计期间显示数据源配置向导。若用户选择一个对象(),并单击finish,我将得到一个字符串,如
“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)));
    }
}