避免在Type.GetType()中给出命名空间名称。

36
Type.GetType("TheClass");

如果namespace不存在,则返回null,例如:

Type.GetType("SomeNamespace.TheClass"); // returns a Type object 

有没有办法避免给出namespace名称?


4
你知道在一个已经添加了很多引用并且尝试解析类型的文件中,可能会有多个不同名称为TheClass的类存在吗?你应该传递完全限定名称(包括命名空间),就像在文档中引用自己时写下名字和姓氏一样。如果有多个TheClass类别存在,编译器该使用哪一个呢?命名空间决定了具体是哪一个。 - Davide Piras
我会抛出 ArgumentException 而不是仅返回 null。如果没有 Namespace,你无法区分。 - gdoron
可能是从类型的部分名称获取System.Type的重复问题。 - nawfal
5个回答

58

我使用了一个帮助方法,它搜索所有已加载的Assembly并查找与指定名称匹配的Type。尽管在我的代码中只有一个Type结果被期望,但它支持多个结果。我验证了每次使用它时仅返回一个结果,并建议您也这样做。

/// <summary>
/// Gets a all Type instances matching the specified class name with just non-namespace qualified class name.
/// </summary>
/// <param name="className">Name of the class sought.</param>
/// <returns>Types that have the class name specified. They may not be in the same namespace.</returns>
public static Type[] getTypeByName(string className)
{
    List<Type> returnVal = new List<Type>();

    foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
    {
        Type[] assemblyTypes = a.GetTypes();
        for (int j = 0; j < assemblyTypes.Length; j++)
        {
            if (assemblyTypes[j].Name == className)
            {
                returnVal.Add(assemblyTypes[j]);
            }
        }
    }

    return returnVal.ToArray();
}

25
针对问题作出回答是正确的做法,而非参与上面的争吵。+1。 - John Livermore
2
另一个答案来自了一个知道的人,而不是使用“不要使用命名空间bla bla”的人。感谢您的回答。 - Furkan Gözükara
很棒,做到了它所说的。我想要添加的主要事项是使用assemblyTypes[j].Name.EqualsIgnoreCase(className)。 - sirthomas

23

不需要把事情复杂化。

AppDomain.CurrentDomain
    .GetAssemblies()
    .SelectMany(x => x.GetTypes())
    .FirstOrDefault(t => t.Name == "MyTypeName");

使用Where代替FirstOrDefault来获取所有结果。


0

简单的缓存版本

只需执行一次...

        nameTypeLookup = typeof(AnyTypeWithin_SomeNamespace).Assembly
            .DefinedTypes.Where(t => t.DeclaringType == null)
            .ToDictionary(k => k.Name, v => v);

用法 - 通过字典多次查找

nameTypeLookup["TheClass"];

这是优雅且可重用的代码,与其他答案相比最符合我的使用需求(其他答案也可以工作)。不确定为什么你会被踩,因为这个代码 a)能够工作,b)如果你想通过短名称加载类型而不是冗长的程序集限定名称,并且你想在自己特定的程序集范围内进行作用域,那么这个代码是优雅/简单/简洁的,它可以锚定到一个已知的类型,例如ORM/EM中的主表/实体。 - Tim
1
此外,在我对您的答案的实现中,我可以直接使用this.GetType().Assembly...而不需要获取其他类型,因为我的类通过短名称引用其他类与目标类在同一个程序集中。return this.GetType().Assembly.DefinedTypes.First(t => t.Name == ClassName); - Tim

0
根据这里发布的答案,我在我的扩展静态类中使用了这个。
public static readonly IEnumerable<Type> cachedAssembliesTypes =
AppDomain.CurrentDomain
         .GetAssemblies()
         .SelectMany(x => x.GetTypes());

public static IEnumerable<Type>? GetTypesByName(this string typeName)
{
    Type? resultType = null;
    try
    {
        resultType = Type.GetType(typeName);
    }
    catch 
    {
        return null;
    }

    return resultType != null ?
        new Type[] {resultType} :
        cachedAssembliesTypes.Where(t => t.Name == typeName);
}

public static Type? GetTypeByName(this string typeName)
    => GetTypesByName(typeName)?.FirstOrDefault();

-6

这是方法期望获得的参数,所以不行。

typeName:由其命名空间限定的类型名称。

MSDN

您如何区分具有相同名称但不同命名空间的两个类?

namespace one
{
    public class TheClass
    {
    }
}

namespace two
{
    public class TheClass
    {
    }
}

Type.GetType("TheClass") // Which?!

4
@NIleshLanke,希望你意识到微软并不是按照你的需求设计.NET框架,而是为了在更广泛的场景中使用而构建的。例如,在两个不同的命名空间中具有相同类名的情况下。 - Darin Dimitrov
2
@gdoron,为什么在这篇文章中坚持认为它无法完成,而已经有一个被接受的答案表明它是可以完成的呢? - user924069
3
@gdoron,不需要。上面的答案已经明确地告诉你该怎么做了。 - user924069
9
@gdoron,你需要关注用户实际想要的,而不仅仅是问题标题的字面意思。 这就像我问是否可以喝西瓜,而你只回答“不可以”,然后Fr33dan走过来说:“如果你把它切碎丢进Nutribullet里,你就可以了”——那才是我真正想知道的。 我认为可以放心地说,在这种情况下,用户只是想找到一种不必指定命名空间即可获取类型的方法。 - Bracher
4
@gdoron,请阅读此链接:http://stackoverflow.com/help/how-to-answer,特别是关于“回答问题”部分。 - Bracher
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接