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

news/2025/1/8 22:17:18/

在 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/news/1561646.html

相关文章

OpenCV 4.5至4.10版本更新概述

OpenCV 4.5至4.10版本更新概述 OpenCV 从 4.5 到 4.10 版本的更迭中,每个版本都引入了新功能、优化和修复。以下是主要版本的更新内容概述: OpenCV 4.5.x 系列 4.5.0 (2020年10月) 新增对 YOLOv4 的支持。引入 DNN 模块的改进,包括对 ONNX …

Ruby语言的编程范式

Ruby语言的编程范式 引言 Ruby是一种动态、开源、面向对象的编程语言,最早由日本计算机科学家Matz(松本行弘)于1995年开发。Ruby以其简洁的语法和强大的功能而广受欢迎,特别是在Web开发领域。Ruby对开发者的友好性以及其设计哲学…

拥有23种PDF/图片转换 数据提取 - 免费在线工具

All ComPDFKit Online PDF Tools | ComPDFKit 1. 数据提取 • 提取全部: 从PDF和图片中提取所有文本、表格和图片,并保存为JSON格式。 • 仅提取文本: 仅从PDF和图片中提取所有文本,并保存为TXT和JSON格式。 • 仅提取表格: 仅从PDF和图片中提取表格&am…

主成分分析(PCA)算法

主成分分析(PCA)算法 主成分分析(Principal Component Analysis, PCA)是一种常用的无监督降维算法,主要用于数据的特征提取和维度压缩。其目标是将高维数据映射到低维空间,同时尽可能保留数据的主要信息。…

HTML5语义化编程

常见的 HTML5 语义化标签 <header>&#xff1a;定义文档或节的头部区域&#xff0c;通常包含标题、logo、导航链接等。<nav>&#xff1a;表示导航链接的部分&#xff0c;适合用来包裹主要的导航菜单。<main>&#xff1a;标识文档的主要内容&#xff0c;每个…

Linux初识——基本指令

我们在linux下输入各种指令&#xff0c;其实就相当于在windows中的相关操作&#xff0c;比如双击&#xff0c;新建文件夹等。 以下是相关基本指令基本用法 一.ls&#xff08;显示当前目录下的所有文件和目录&#xff09; 那如何显示当前目录&#xff08;我们所在的位置&…

F#语言的数据结构

F#语言的数据结构浅析 F#是一种函数式编程语言&#xff0c;属于.NET生态系统。作为一种强类型语言&#xff0c;F#支持丰富的数据结构&#xff0c;使得编写复杂算法和数据处理变得更加高效和便利。在这篇文章中&#xff0c;我们将深入探讨F#的主要数据结构&#xff0c;包括元组…

STM32H7的SPI总线基础知识备忘

一 概念 STM32H7的SPI支持4到32bit数据传输&#xff0c;而STM32F1和F4系列仅支持8bit或者16bit。 STM32H7的主频400MHz时&#xff0c;SPI1, 2, 3最高通信时钟是100MHz&#xff0c;而SPI4, 5, 6是50MHz。 STM32H7的MISO和MOSI引脚功能可以互换&#xff0c;使用比较灵活。 …