如何获取一个程序集的根命名空间?

57

给定一个 System.Reflection.Assembly 实例。

16个回答

73

当我想从当前程序集的清单资源流中加载资源时,我经常遇到这种两难选择。

事实上,如果你使用Visual Studio将文件嵌入程序集作为资源,其清单资源名称将派生自在Visual Studio项目中定义的程序集的默认命名空间。

我想到的最好的解决方案(避免在某个地方将默认命名空间硬编码为字符串)是始终确保你的资源加载代码是始终发生在与默认命名空间相同的类内部,然后可以使用以下近乎通用的方法。

此示例正在加载嵌入式模式。

XmlSchema mySchema;
string resourceName = "MyEmbeddedSchema.xsd";
string resourcesFolderName = "Serialisation";
string manifestResourceName = string.Format("{0}.{1}.{2}",
    this.GetType().Namespace, resourcesFolderName, resourceName);
using (Stream schemaStream = currentAssembly.GetManifestResourceStream(manifestResourceName))
    mySchema = XmlSchema.Read(schemaStream, errorHandler);

请参阅:如何获取程序集的命名空间?

编辑:还注意到我正在回答的问题有一个非常详细的答案,位于http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/3a469f5d-8f55-4b25-ac25-4778f260bb7e

另一个编辑,以防有相同问题的人寻找:在此处解决资源加载问题的出色思路:如何获取项目csproj(VS 2008)的默认命名空间


2
当我的程序集名称和项目的“根命名空间”不匹配时,遇到了嵌入资源解析问题。感谢有帮助的帖子。 - Ivaylo Slavov
1
你不能创建一个没有命名空间的类并使用typeof(DefaultNamespaceHelper).Namespace吗? - Drakarah
这个答案不应该得到赞同,因为它会误导那些正在寻找实际问题答案的人。这个答案仅仅获取了你所在类的命名空间。它绝对不能获取当前程序集的根命名空间,而这正是问题所在。Darren的被接受的答案是正确的。 - Neo
1
@Neo,你所描述的所有注意事项都已经在答案中写明了。当然,它回答了一个不同的问题,但人们来到这里是为了回答我正在回答的问题。对于想知道如何找到他们所在类的命名空间的人来说,这是有帮助的。 - Lisa

52

不可能。没有指定“Root”名称空间。选项中的默认命名空间是Visual Studio的东西,而不是 .net 的东西。


4
Lisa用户的下面帖子实际起作用,因此该答案被标记为答案,但没有适当的原因。 - Roboblob
8
@Roboblob Darren的回答从技术上讲是正确的。我的回答仅在你想要在VS中构建项目的情况下,在大约95%的情况下会更加有用。 - Lisa
1
只有因为想象力的失败才会变得不可能。请参见https://dev59.com/HG445IYBdhLWcg3wZJYn。 - David A. Gray
1
可以。请参见 https://dev59.com/HG445IYBdhLWcg3wZJYn。 - David A. Gray
这是一个.NET的事情,就像Lisa的回答所说的那样。 - John

10

我刚刚创建了一个名为Root的空内部类,并将其放在项目根目录(假设这是您的根名称空间)。然后,我在需要根名称空间的任何地方都使用它:

typeof(Root).Namespace;

我最后会得到一个未使用的文件,但它是干净的。


当需要在同一程序集中使用,但不想硬编码时非常有用。 - M. Jahedbozorgan

10

在给定的程序集中可能存在任意数量的命名空间,它们并不要求都从一个公共的根开始。最好的方法是反射程序集中所有类型,并构建一个包含其中唯一命名空间的列表。


5

程序集不一定有根命名空间。 命名空间和程序集是正交的。

您可能正在寻找的是在该程序集中查找类型,然后找出其命名空间。

您可以使用GetExportedTypes()成员来完成此操作,然后从返回的Type句柄之一使用Namespace属性。

但同样不能保证所有类型都在同一个命名空间中(甚至不在同一个命名空间层次结构中)。


3

我在我的WPF应用程序中使用typeof(App).Namespace。 App类对于任何WPF应用程序都是必需的,并且位于根目录中。


2
GetType(frm).Namespace

frm是启动窗体。


1
如果启动窗体不在根命名空间中怎么办? - Patrick Hofman

2

获取类型可以给你一个在程序集中定义的Type对象列表。该对象具有命名空间属性。请记住,一个程序集可以有多个命名空间。


1

命名空间与程序集无关 - 命名空间和程序集中的类之间的任何映射都纯粹是由命名约定(或巧合)决定的。


4
虽然我同意,但值得注意的是,Visual Studio项目有一个默认命名空间,如果你使用Visual Studio嵌入资源,那么该资源的清单资源名称将派生自默认命名空间,并且如果你始终使用Visual Studio构建程序集,则该资源看起来似乎是由程序集本身定义的。而且面对现实情况,这种情况相当普遍。 - Lisa

1
不,你无法确定在一个程序集的项目文件中设置的默认命名空间...但是你可以假设大多数在程序集中声明的类型都在默认命名空间中。我的解决方案寻找最流行的命名空间根,其中至少80%(任意选择)的类型包含在其中:
public static string? GetDefaultNamespace(this Assembly assembly, double threshold = 0.8)
{
    var types = assembly.GetTypes();
    int partIndex = 0;
    var parts = new List<string>();
    var ranked = types
        .Where(_ => _.Namespace != null)
        .GroupBy(_ => _.Namespace)
        .Select(_ => new { Parts = _.Key!.Split('.'), Count = _.Count() })
        .Where(_ => _.Parts.Length > partIndex)
        .GroupBy(_ => _.Parts[partIndex])
        .OrderByDescending(_ => _.Sum(x => x.Count))
        .ToArray();
    while (ranked.Any() && ranked[0].Sum(_ => _.Count) >= types.Length * threshold)
    {
        parts.Add(ranked[0].Key);
        partIndex++;
        ranked = ranked[0]
            .Where(_ => _.Parts.Length > partIndex)
            .GroupBy(_ => _.Parts[partIndex])
            .OrderByDescending(_ => _.Sum(x => x.Count))
            .ToArray();
   }
   return string.Join('.', parts);
}

1
有趣的解决方案。将阈值设为参数,这样调用者可以选择他们想要的置信度。 - dodexahedron
1
@dodexahedron - 不错的决定。 - RossWright

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