如果 typeof(Xyz) 存在,为什么 System.Type.GetType("Xyz") 返回 null?

发布于 2024-09-24 21:30:57 字数 1183 浏览 4 评论 0 原文

我在我的(巨大的).NET 4 项目中遇到了奇怪的行为。在代码中的某个时刻,我指的是完全限定类型,例如:

System.Type type = typeof (Foo.Bar.Xyz);

稍后,我这样做:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz");

然后返回 null。我无法理解为什么会发生这种情况,因为我的类型名称是正确的,并且我已经检查了其他类型并且它们得到了正确的解决。此外,以下 LINQ 查询查找类型:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
            from assemblyType in assembly.GetTypes ()
            where assemblyType.FullName == typeName
            select assemblyType;

System.Type type = types.FirstOrDefault ();

System.Type.GetType 可能失败有什么原因吗?

我最终不得不求助于这段代码而不是 GetType

System.Type MyGetType(string typeName)
{
    System.Type type = System.Type.GetType (typeName);

    if (type == null)
    {
        var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
                    from assemblyType in assembly.GetTypes ()
                    where assemblyType.FullName == typeName
                    select assemblyType;

        type = types.FirstOrDefault ();
    }

    return type;
}

I have come across a strange behaviour in my (huge) .NET 4 project. At some point in the code, I am referring to a fully qualified type, say:

System.Type type = typeof (Foo.Bar.Xyz);

later on, I do this:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz");

and I get back null. I cannot make sense of why this is happening, because my type name is correct, and I have checked with other types and they get resolved properly. Moreover, the following LINQ query finds the type:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
            from assemblyType in assembly.GetTypes ()
            where assemblyType.FullName == typeName
            select assemblyType;

System.Type type = types.FirstOrDefault ();

Are there any reasons why System.Type.GetType could fail?

I have finally had to resort to this piece of code instead of GetType:

System.Type MyGetType(string typeName)
{
    System.Type type = System.Type.GetType (typeName);

    if (type == null)
    {
        var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
                    from assemblyType in assembly.GetTypes ()
                    where assemblyType.FullName == typeName
                    select assemblyType;

        type = types.FirstOrDefault ();
    }

    return type;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

阳光下的泡沫是彩色的 2024-10-01 21:30:57

如果您只给出一个类名(当然,确实需要在命名空间方面进行完全限定)Type.GetType(string) 将仅在当前正在执行程序集和 mscorlib。如果要从任何其他程序集获取类型,则需要指定包括程序集信息的绝对完整名称。正如弗朗索瓦所说, Type.AssemblyQualifiedName< /a> 是了解这一点的好方法。这是一个例子:

using System;
using System.Windows.Forms;

class Test
{
    static void Main()
    {
        string name = typeof(Form).AssemblyQualifiedName;
        Console.WriteLine(name);

        Type type = Type.GetType(name);
        Console.WriteLine(type);
    }
}

输出:

System.Windows.Forms.Form,System.Windows.Forms,版本=4.0.0.0,文化=中性,
公钥令牌=b77a5c561934e089
System.Windows.Forms.Form

请注意,如果您使用强命名程序集(如本例中的 Form),则必须包含所有程序集信息 - 版本控制、公共密钥令牌等。

如果您使用非强命名的程序集,则更容易 - 例如:

Foo.Bar.Baz, MyCompany.MyAssembly

对于命名空间 Foo.Bar 中名为 Baz 的类型,在程序集中MyCompany.MyAssembly。请注意末尾缺少“.dll” - 这是文件名的一部分,但不是程序集名称。

您还应该了解 C# 名称和 CLR 名称之间的差异(例如嵌套类和泛型)。例如,typeof(List<>.Enumerator) 的名称为 System.Collections.Generic.List`1+Enumerator[T]。泛型方面很难解决,但嵌套类型位很简单 - 它只是用“+”而不是“.”表示。你会在 C# 中使用。

If you just give a class name (which does need to be fully-qualified in terms of the namespace, of course) Type.GetType(string) will only look in the currently executing assembly and mscorlib. If you want to get types from any other assembly, you need to specify the absolutely full name including the assembly information. As François says, Type.AssemblyQualifiedName is a good way of seeing this. Here's an example:

using System;
using System.Windows.Forms;

class Test
{
    static void Main()
    {
        string name = typeof(Form).AssemblyQualifiedName;
        Console.WriteLine(name);

        Type type = Type.GetType(name);
        Console.WriteLine(type);
    }
}

Output:

System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
System.Windows.Forms.Form

Note that if you're using a strongly named assembly (like Form in this case) you must include all the assembly information - versioning, public key token etc.

If you're using a non-strongly-named assembly, it's easier - something like:

Foo.Bar.Baz, MyCompany.MyAssembly

for a type called Baz in namespace Foo.Bar, in assembly MyCompany.MyAssembly. Note the absence of ".dll" at the end - that's part of the filename, but not the assembly name.

You should also be aware of the differences between C# names and CLR names for things like nested classes and generics. For example, typeof(List<>.Enumerator) has a name of System.Collections.Generic.List`1+Enumerator[T]. The generics side is tricky to work out, but the nested type bit is easy - it's just represented with a "+" instead of the "." you'd use in C#.

浅听莫相离 2024-10-01 21:30:57

据我所知,GetType 在名为 Foo.Bar.dll 的程序集中查找“Xyz”,我假设它不存在。

GetType 依赖于您在程序集中传递到 Xyz 的确切路径。
程序集和命名空间不必相关。

尝试 System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) 并查看是否有效。

您在 LINQ 示例中找到它的原因是您正在使用 GetAssemblies 来获取已加载到当前执行上下文中的程序集,从而获得查找程序集中所有类型所需的详细信息。

As far as I know GetType looks for "Xyz" in an assembly named Foo.Bar.dll and I'm assuming it doesn't exist.

GetType relies on your passing the exact path to Xyz in the assembly.
Assembly and namespace don't have to be related.

Try System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) and see if that works.

The reason you find it with your LINQ example is that you are using GetAssemblies which obtains the assemblies that have been loaded into the current execution context and thus has the details it needs to find all the types within the assemblies.

帝王念 2024-10-01 21:30:57

来自 MSDN 文档(我的重点):

如果 typeName 包含命名空间但不包含程序集名称,则此方法按顺序仅搜索调用对象的程序集和 Mscorlib.dll。如果 typeName 使用部分或完整的程序集名称完全限定,则此方法在指定的程序集中搜索。如果程序集具有强名称,则需要完整的程序集名称。

From the MSDN documentation (my emphasis):

If typeName includes the namespace but not the assembly name, this method searches only the calling object's assembly and Mscorlib.dll, in that order. If typeName is fully qualified with the partial or complete assembly name, this method searches in the specified assembly. If the assembly has a strong name, a complete assembly name is required.

濫情▎り 2024-10-01 21:30:57

我刚刚偶然发现了一个类似的问题,并想将其留在这里

首先,您可以在字符串中指定 AssemblyName

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name");

但这仅适用于没有强名称的程序集。西蒙斯的回答中已经有解释 如果程序集具有强名称,则需要完整的程序集名称。

我的问题是我必须解析 System.Dictionary< /code> 在运行时从字符串中获取。对于 Dictionary 这可能很简单,但是对于 Dictionary 呢?

这会导致

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]";

但我不想写强名称。特别是因为我不想包含版本,因为我计划用我的代码针对多个框架。

所以这是我的解决方案

    privat statice void Main()
    {
        var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]";
        var type = Type.GetType(typeName, ResolveAssembly, ResolveType);
    }

    private static Assembly ResolveAssembly(AssemblyName assemblyName)
    {
        if (assemblyName.Name.Equals(assemblyName.FullName))
            return Assembly.LoadWithPartialName(assemblyName.Name);
        return Assembly.Load(assemblyName);
    }

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase)
    {
        return assembly != null
            ? assembly.GetType(typeName, false, ignoreCase)
            : Type.GetType(typeName, false, ignoreCase);
    }

Type.GetType(...) 有一个重载,它接受一个用于组装和类型解析的函数,它很整洁。 Assembly.LoadWithPartialName 已弃用,但如果将来将其删除,我可以考虑替换(迭代当前 AppDomain 中的所有程序集并比较部分名称)。

I just stumbled upon a similar problem and want to leave this here

First of all your can specify the AssemblyName in the string

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name");

However this only works for assemblies without a strong name. The explaination is already in Simons answer If the assembly has a strong name, a complete assembly name is required.

My problem was I had to resolve a System.Dictionary<?,?> from a string at runtime. For a Dictionary<int, string> this might be easy but what about a Dictionary<int, Image>?

this would result in

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]";

But I don't want to write the strong name. Especially because I don't want to include the versions since I am planning to target multiple frameworks with my code.

So here is my solution

    privat statice void Main()
    {
        var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]";
        var type = Type.GetType(typeName, ResolveAssembly, ResolveType);
    }

    private static Assembly ResolveAssembly(AssemblyName assemblyName)
    {
        if (assemblyName.Name.Equals(assemblyName.FullName))
            return Assembly.LoadWithPartialName(assemblyName.Name);
        return Assembly.Load(assemblyName);
    }

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase)
    {
        return assembly != null
            ? assembly.GetType(typeName, false, ignoreCase)
            : Type.GetType(typeName, false, ignoreCase);
    }

Type.GetType(...) has an overload which acceps a func for assembly and type resolving which in neat. Assembly.LoadWithPartialName is deprecated but if it's dropped in the future I could think of an replacement (iterate all assemblies in the current AppDomain and compare the partial names).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文