C# для профессионалов. Том II - Симон Робинсон
Шрифт:
Интервал:
Закладка:
// package_samples.java
package samples.on; // отображает прямо в папку, где находится файл класса
public class Packaging {
int x;
public class Internal {
// находится автоматически в том же пакете
}
public static void main(String args[]) {
}
}
class Internal {
// находится автоматически в том же пакете
}
Примеры того, как этот код может выполняться, приведены ниже. Это, конечно, предполагает, что файл класса был сделан доступным для JRE:
□ Из командной строки:
java samples.on.Packaging
□ Как непосредственная ссылка в коде:
// Referencer.java
public class Referencer {
samples.on.Packaging pack = new samples.on.two.three.Packaging();
□ Используя директиву import, можно опустить полностью квалифицированные имена пакетов, поэтому Referencer запишется как:
// Referencer.java
import samples.on.*;
public class Referencer{
Packaging pack = new Packaging();
}
Помещение класса в пространство имен достигается в C# с помощью ключевого слова namespace с идентификатором и заключением целевого класса в скобки. Вот пример:
// namespace_samples.cs
namespace Samples.On {
using System;
public class Example {
public Example() {
}
}
}
Преимущество использования скобок для явного ограничения пространства имен состоит в том, что это задает определенный пользователем тип в реальном классе, определенном в файле, а не в самом файле. В Java файлы и папки косвенно представляют структуры языка, так как они аналогичны классам и пакетам, содержащим эти классы. В C# файлы не связаны принудительно с чем-либо, поэтому они становятся местом, где располагается определение класса, а не частью какой-либо структуры языка. Пространства имен также не связаны с папками. Следовательно, в одном файле можно ввести несколько пространств имен без всяких ограничений. Можно, например, добавить определение нового класса и поместить его в новое пространство имен в том же файле и по-прежнему оставаться в границах языка:
// namespace_samples.cs
namespace Samples.On {
using System;
public class Example {
public Example() {
}
}
}
namespace Com.Cslib {
using System;
using System.Collections;
public class AddLib {
public AddLib() {
}
public int operationAdd(int a, int b) {
return a + b;
}
}
}
Пространства имен вводятся с помощью директивы using <namespace name>, где <namespace name> является именем пространства имен. В C# не требуется использовать *, так как директива using неявно импортирует все элементы указанного пространства имен. Другим преимуществом является то, что пространства имен могут быть добавлены исключительно в конкретный класс. Хотя классы Example и AddLib выше определены в файле namespace_samples.cs. Example не имеет доступа к пространству имен System.Collections, несмотря на то, что AddLib его имеет. Однако инструкция import из Java не является специфической для класса. Она импортирует указанные элементы в файл. Вновь обратимся к х.java.
// х.java
public class x {
}
class у {
}
class z {
}
Если добавить инструкцию импорта, такую как import java.util.Hashtable, все классы, определенные внутри этого файла, будут иметь доступ к классу Hashtable. Код ниже будет компилироваться:
// x.java
package samples;
import java.util.Hashtable;
public class x {
Hashtable hash = new Hashtable();
}
class у {
Hashtable hash = new Hashtable();
}
class z {
Hashtable hash = new Hashtable();
}
Пространства имен можно также определять внутри другого пространства имен. Этот тип гибкости недоступен в Java без создания подкаталогов. Приведенное выше пространство Com.Cslib можно расширить следующим образом:
namespace Com.Cslib {
using System;
public class AddLib {
public AddLib() {
}
public int operationAdd(int a, int b) {
return a + b;
}
}
namespace Ext {
public class AddLib {
public AddLib() {
}
public int operationAdd(int a, int b) {
return a + b;
}
}
}
}
Пакет Java com.javalib можно расширить, чтобы отобразить приведенный выше код, создав новую папку EXT в каталоге comjavalib. В этой папке создается файл исходного кода AddLib.java следующим образом:
package com.javalib.ext;
public class AddLib {
public AddLib() {
}
public int operationAdd(int a, int b) {
return a + b;
}
}
Отметим, что имя пакета было расширено для этого класса до com.javalib.ext.
Внутреннее пространство имен и подпакеты доступны с помощью оператора точки "."; следовательно, можно было в C# извлечь расширенный AddLib с помощью нотации Com.Cslib.Ext.AddLib. В Java можно было бы использовать com.javalib.ext.AddLib.
Приведенный выше пример показывает одно сходство между пакетами Java и пространствами имен C#. Даже если они не используются для внешнего представления, пространства имен, так же как и пакеты, предоставляют прекрасный способ создания глобально уникальных типов, свою собственную песочницу в мире сборок независимых поставщиков. В той степени насколько это имеет отношение к C#, Com.Cslib.AddLib является не тем же классом, что и Com.Cslib.Ext.AddLib.
Классы Java являются частью пакета, нравится им это или нет. Все классы, созданные без указания пакета, предполагают включение в пакет по умолчанию. C# имитирует эту функциональность. Даже если не объявить пространство имен, оно будет создано по умолчанию. Оно присутствует в каждом файле и доступно для использования в именованных пространствах имен. Так же как в Java нельзя изменить информацию о пакете, пространства имен нельзя модифицировать. Пакеты могут охватывать несколько файлов в одной папке, пространство имен может охватывать несколько файлов в любом числе папок и даже в нескольких сборках (сборки будут рассмотрены в следующем разделе). Два класса, охватываемые пространством имен А, которые определены в отдельных файлах и существуют в отдельных папках, оба являются частью пространства имен А.
Чтобы получить доступ к элементу в пространстве имен, необходимо либо использовать полностью квалифицированное имя типа (в приведенном выше примере это Com.Cslib.AddLib) или импортировать элемент пространства имен в текущее пространство имен, используя директиву using. Отметим, что по умолчанию доступность типов данных внутри пространства имен является внутренней. Необходимо явно отметить типы данных как открытые (public), если требуется сделать их доступными без полной квалификации, но придерживаться такой стратегии строго не рекомендуется. Никакие другие модификаторы доступа не разрешены. В Java внутренние типы пакета могут также помечаться как final или abstract, или не помечаться вообще (этот доступ по умолчанию открывает их только для потребителей внутри пакета). Модификаторы доступа будут рассматриваться позже в этом приложении.
Последним атрибутом, который относится к пространству имен, но не имеет отношения к пакетам, является возможность задания алиаса для using. Алиасы using существенно облегчают квалификацию идентификатора для пространства имен или класса. Синтаксис очень простой. Предположим, что имеется пространство имен Very.Very.Long.Namespace.Name. Можно определить и использовать алиас using для пространства имен следующим образом:
using WLNN = Very.Very.Long.Namespace.Name;
Конечно, имя псевдонима (алиаса) является произвольным, но должно следовать правилам именования переменных в C#.
Создание и добавление библиотек при компиляции
Ранее, при обсуждении компиляции и единиц компиляции кратко было сказано о концепции библиотек. Если создана библиотека, то необходимо, чтобы она была доступна для всех потенциальных потребителей. В Java это делается добавлением пути доступа к папке, содержащей классы библиотеки, в переменную окружения Classpath. Конечно, чтобы упростить это, можно добавить файлы класса в папке в JAR и поместить путь доступа к файлу jar в Classpath. В любом случае работа загрузчика классов состоит в нахождении всех неразрешенных ссылок, и он будет искать их в Classpath.
C# предоставляет совсем другие механизмы для упаковки классов в библиотеку. По умолчанию все файлы C# в проекте станут частью единицы компиляции при использовании VS.NET. Если применяется командная строка, необходимо будет явно добавлять каждый файл, который должен быть частью единицы компиляции, как описано выше.