C# 中的命名空间与Java和Python中的导入

ops/2025/1/8 20:15:02/

在 C#、Java 和 Python 这三种语言中,命名空间和导入机制都是用来组织和管理代码及其依赖的工具,但它们在具体实现和使用方式上存在一些差异。

在这里插入图片描述

1、问题背景

在 Java 和 Python 世界中,我们可以通过查看源文件来了解所有导入的来源(即我们知道导入类的定义所在文件)。例如:

在 Java 中:

java">import javafoo.Bar;public class MyClass {private Bar myBar = new Bar();
}

我们可以立即看到 Bar 类是从 javafoo 导入的。因此,Bar 在 /javafoo/Bar.java 中声明。

在 Python 中:

python">import pythonbaz
from pythonfoo import Barmy_bar = Bar()
my_other = pythonbaz.Other()

这里,很明显,Bar 来自 pythonfoo 包,而 Other 显然来自 pythonbaz。

在 C# 中:

using foo
using baz
using anothernamespace
...public class MyClass
{private Bar myBar = new Bar();
}

有两个问题:

  1. 我如何知道 Bar 类在哪里声明?它来自 foo 命名空间、bar 命名空间还是 anothernamespace 命名空间?(编辑:不使用 Visual Studio)
  2. 在 Java 中,包名对应于目录名(或者说,这是一种非常强的约定)。因此,当您看到一个类的来源包时,您就知道它在文件系统中的目录。在 C# 中,似乎没有这样的命名空间约定,或者我遗漏了什么?那么,我不知道要查找哪个目录和文件(在弄清楚该类来自哪个命名空间之后)。

澄清编辑:我知道 Python 和/或 Java 允许使用通配符导入,但这些语言中的“文化”不赞同它们(至少在 Python 中是这样,我不确定 Java 中是否是这样)。此外,在 Java 中,IDE 通常会帮助您创建最小导入(正如 Mchl. 在下面评论的那样)。

2、解决方案

答案 1:

  1. 实际上,您也可以在 Java 中执行相同的操作:
java">import java.util.*;
import java.io.*;...InputStream x = ...;

InputStream 来自 java.util 还是 java.io?当然,您可以选择不使用该功能。

现在,从理论上讲,这意味着当您使用文本编辑器查看时,您无法分辨 C# 中的类型来自哪里…但在实践中,我发现这不是问题。您实际查看代码并无法使用 Visual Studio 的频率是多少?

  1. 当然,您也可以在 .NET 中使用相同的约定 - 而且我确实这样做了,尽管我没让空目录向上延伸…因此,如果我创建一个默认命名空间为 X.Y 的项目,那么 X.Y.Foo 将位于 Foo.cs 中,而 X.Y.Z.Bar 将位于 Z\Bar.cs 中。

Visual Studio 默认也会这样做 - 如果您创建一个子文件夹,它将使用基于项目默认值和文件夹结构的命名空间创建新类。

当然,您也可以在任何旧文件中声明类型 - 但大多数人都会遵循使用与相应文件名相对应的类型声明的常规约定。在泛型使委托声明变得更少见之前,我曾经有一个 Delegates.cs 文件,其中包含特定命名空间的所有委托声明(而不是有一堆单一声明文件),但现在这不再成为问题。

答案 2:

  1. 你是对的。乍一看没有“直接”的方法来知道您的类来自哪里,但是,正如您所说,您可以在 IDE 中跳转到它。但以这种方式声明类只是最短的方式来做到这一点。如果您愿意,假设您的 Bar 类来自 Foo 类,您可以声明它
private foo.Bar myBar = new foo.Bar();

这样可以帮助您在第一时间就知道您的类来自哪里。

  1. 当您添加对类的引用时,“添加引用”窗口会为您提供您正在寻找的信息。

如果您想在声明它之后了解它们来自哪里,则有一个名为“解决方案资源管理器”的窗口,您可以在“引用”树节点下找到这些信息。

您可以将其设置为始终可见(默认情况下它是可见的)

答案 3:

对于 Java 和 Python,这确实是一个约定问题 - 导入您需要的类,而不是使用通配符导入整个包。

在 C# 中,您不能对所需的特定类执行 using 指令,因为它只适用于命名空间(如下面的错误所示)。看起来 C# 仍然忠于 C++ 的命名空间概念,并将其与 #include 指令合并为一种引用外部类的简单方法。

using System.Net.Sockets.Socket; // Gives the following error:// A using namespace directive can only be applied to namespaces; 
// 'System.Net.Sockets.Socket' is a type not a namespace

关于双重 Bar 声明,很简单 - 如果编译器没有办法知道,它会给出错误:

using Foo; // Has class Bar {}
using Goo; // Has class Bar {}Bar b = new Bar(); // Gives the following error:
// 'Bar' is an ambiguous reference between 'Foo.Bar' and 'Goo.Bar'

答案 4:

您如何知道 Bar 类在哪里声明?它来自 foo 命名空间、bar 命名空间还是 anothernamespace 命名空间?当然,Visual Studio 允许我跳转到那里,但如果我只是在编辑器中快速查看源文件怎么办?

从本质上讲,您不知道 - 但 IntelliSense 正在提供帮助。您实际上无法通过快速浏览代码来确定,但您可以用光标将鼠标悬停在符号上,例如。但这在 Python 中也是可能的:

python">from foobar import *
from bazbaz import *a_bar = Bar()

现在 Bar 从哪里来?

在 C# 中,似乎没有这样的命名空间约定,或者我遗漏了什么?那么,我知道要查找哪个目录和文件(在弄清楚该类来自哪个命名空间之后)。

不,程序集不对应于目录结构,我认为这是一件好事。解决方案资源管理器提供了一个对添加到项目的所有引用的视图。这些引用是程序集,它们以 PE 文件的形式具体表示在计算机上的某个位置。您可以轻松查看引用的属性,以查看物理文件位于何处。编辑:为了不与本主题中的其他答案相矛盾并造成混淆:我说程序集名称不对应目录名称的意思是它实际上并没有被强制执行。

答案 5:

我不知道其他项目的情况,但我敢肯定,在我参与的每一个 .NET 项目中,我们都使用了这个约定,即命名空间始终对应于文件夹名称(除了最外层的命名空间对应于该命名空间所属的程序集)。

答案 6:

通常,当您将鼠标悬停在类型名称上时,工具提示会显示一些额外信息。否则,您始终可以右键单击类型名称,然后“转到定义”。

这几种语言虽然在命名空间和导入机制的实现细节上各有特色,但它们共同的目标是提高代码的可管理性、可重用性和组织性。


http://www.ppmy.cn/ops/148550.html

相关文章

CSS进阶和SASS

目录 一、CSS进阶 1.1、CSS变量 1.2、CSS属性值的计算过程 1.3、做杯咖啡 1.4、下划线动画 1.5、CSS中的混合模式(Blending) 二、SASS 2.1、Sass的颜色函数 2.2、Sass的扩展(extend)和占位符(%)、混合(Mixin) 2.3、Sass的数学函数 2.4、Sass的模块化开发 2.5、Sass…

解决报错net.sf.jsqlparser.statement.select.SelectBody

在我们项目集成mybatis-plus时,总会遇到奇奇怪怪的报错,比如说下面的这个报错 而这个报错,是告诉我们的分页依赖冲突,要加个jsqlparser依赖来解决这个冲突,也相当于平衡,但是可能因为我们版本的不匹配,还是会报错,例如下面这样 但是我们是不知道到底是什么依赖冲突的,这个时候就…

《前端web开发-CSS3基础-1》

文章目录 《前端web开发-CSS3基础》1.CSS引入方式2.选择器-标签和类3.选择器-id和通配符选择器4.画盒子5.字体修饰属性6.字体大小、粗细和倾斜6.1字体大小6.2 字体粗细6.3字体倾斜 7.行高8.字体族9.font复合属性10.缩进、对齐和修饰线10.1 文本缩进10.2 文本和图片对齐10.3 文本…

蓝桥杯算法|练习记录

位运算 按位与运算符(&) 运算规则:两位同时为1,结果才为1,否则结果为0。例如, -3(在计算机中表示为1101)&5(0101) 0101(即十进制的1&…

SpringSecurity抛出异常但AccessDeniedHandler不生效

文章目录 复现原因 复现 Beanpublic SecurityFilterChain securedFilterChain(HttpSecurity http) throws Exception {//...//异常http.exceptionHandling(except -> {except.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());except.accessDeniedHandle…

数据库---HSQLDB使用教程详解

本学校期末的课程设计要求使用HSQLDB数据库,作为一个小众且轻量的数据库,很少人接触过,再加上同学们都问这个方面,所以就出教程,展示怎么使用HSQLDB。 第一步:启动HSQLDB 下载HSQLDB的jar包,因…

MVCC实现原理及其作用

这里写自定义目录标题 为什么要有MVCC?如何实现?Read View以及可重复读的隔离原理读已提交是如何实现的?总结 为什么要有MVCC? 从用户需求出发,数据库想要实现什么功能呢?事务想要实现隔离性,也…

前端如何处理后端传入的复杂数据格式

在前后端联调过程中不难发现,有时候从后端获取到的数据格式并不是我们所想要的格式,这时候就需要我们自己动手去处理了。最近在开发项目过程中也是遇到了很多传入的数据格式和自己所想要展示的有所区别,这里就先记录一下吧,总结总…