Отталкнемся от директивы/оператора using в C# и посмотрим что там есть в Java.
using
позволяет использовать типы описанные в других пространствах имен без указания fully-qualified-name
Например:
using MyApplication.MyPackage;
// ...
var myClass = new MyClass();
тут мы можем использовать myClass
не указывая молный путь к классу MyApplication.MyPackage.MyClass
Псевдонимы можно создавать для пространства имен или конкретных типов как показанно ниже
using MyPackageAlias = MyApplication.MyPackage;
// or for type alias
using ClassToUse = MyApplication.MyPackage.MyClass;
С помощью using
можно сделать псевдоним на параметризированный generic:
using IntListAlias = List<int>;
//...
var list = new IntListAlias();
list.Add(42);
- Действие
using
распространяется на текущий файл.using
может быть объявлен в начале файла или в начале пространства имен.
С помощью global
, сделав только одно объявление, можно импортировать содержимое пространства имен во всех файлах проекта.
global using MyApplication.MyPackage;
Содержимое покате MyPackage
будет импортировано во все файлы проекта.
Другой способ глобально подключить пространство имен - это файл проекта.
...
<Using Include="MyApplication.MyPackage" />
...
В случае когда наш тип MyClass
содержит статические члены или вложенные типы - мы можем импортировать только их и использовать их без указания типа MyClass
.
Например:
// for class
namespace MyApplication.MyPackage {
class MyClass {
static int Add(int a, int b) {
return a + b;
}
}
}
// we can use it as
using static MyApplication.MyPackage.MyClass;
// ...
var sum = Add(1, 2);
Аналогично для вложенных типов.
Еще пример из документации:
using static System.Console;
using static System.Math;
class Program
{
static void Main()
{
WriteLine(Sqrt(3*3 + 4*4));
}
}
Если мы пишем using MyApplication.MyPackage;
- это значит что мы делаем доступными все типы из пространства имен MyApplication.MyPackage
. Такое поведение вполне точно описывает что мы подразумеваем под wildcard imports когда в Java пишем import MyApplication.MyPackage.*;
. Получается, что wildcard imports для using
в C# - это поведение по умолчанию.
Важно отметить что в C# мы не можем импортировать конкретный тип c using name
using MyApplication.MyPackage.MyClass; // incorrect
такое возможно только с использованием алиаса
using MyClassAlias = MyApplication.MyPackage.MyClass; // correct
// or with same name
using MyClass = MyApplication.MyPackage.MyClass; // correct
но такой подход уже выглядит как будто мы делаем что-то не правильно.
using
в C# может использоваться как оператор для автоматического закрытия объектов имплементирующих IDisposable.
Пример с StreamReader
string txt = String.Empty;
using (StreamReader sr = new StreamReader(filename))
{
txt = sr.ReadToEnd();
}
В этом примере при входе в блок using
будет создан поток StreamReader
, а при выходе этот поток будет закрыт посредствам вызова метода Dispose()
у StreamReader
.
using похож на try-with-resources
в Java.
await using используется для IAsyncDisposable
в using можно передать объект сласса имплементирующего IDisposable
var reader = new StringReader(manyLines);
using (reader) { ... }
using (StringReader left = new StringReader(numbers),
right = new StringReader(letters)) { ... }
Интерфейс для реализации освобождения неуправляемых ресурсов.
Стоит быть аккуратных, возможны проблемы если метод Dispose не будет вызван и ресурсы не будут освобождены. Как решение этой проблемы документация предлагает следующее:
Because the IDisposable.Dispose implementation is called by the consumer of a type when the resources owned by an instance are no longer needed, you should either wrap the managed object in a SafeHandle (the recommended alternative), or you should override Object.Finalize to free unmanaged resources in the event that the consumer forgets to call Dispose.
Интерфейс для реализации асинхронного освобождения неуправляемых ресурсов.
Все немного похоже и немного другое чем в C#. Аналог для using директивы - это import. А для using оператора - это try-with-resources.
Рассмотрим далее подробнее.
Импортировать тип из другого пакета можно так
import MyApplication.MyPackage.MyClass;
// ...
var x = new MyClass();
тут стоит заметить что мы импортируем не все содержимое пакета, а конкретный тип.
В Java мы можем импортировать статический член используя import static
import static MyApplication.MyPackage.MyClass.staticMethid;
это даст нам возможность использовать функцию staticMethid
в коде текущего файла без указания имен пакета и класса.
Пример из документации
import static java.lang.Math.cos;
import static java.lang.Math.PI;
double r = cos(PI * theta);
Нет.
Такой подход в Java будем считать не самым лучшим выбором при написании кода, так как используя это:
import MyApplication.MyPackage.*;
мы можем неявно принести в нашу реализацию класс который мы бы не хотели импортировать.
Поэтому, в Java подход по умолчанию - это импорт только нужного типа вот так:
import MyApplication.MyPackage.MyClass;
В Java try (если он with-resources) умеет "закрывать" объекты. Совсем как using
в C#.
Мы можем использовать объект, реализующий интерфейс AutoCloseable
, как приведено ниже.
try
в этом случае, помимо своей обычной работы по контролю за исключениями, вызовет метод close()
для освобождения ресурсов в конце работы своего блока.
try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
writer.println("Hello World");
}
Все как в C# для IDisposable
только в Java и для AutoCloseable
и название метода другое.
An object that may hold resources (such as file or socket handles) until it is closed. The close() method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header.
Мне показалось что в C# с using
больше способов выстрелить себе в ногу. Возможно это из-за:
using
в C# - это поведение по умолчанию