Отталкнемся от директивы/оператора using в C# и посмотрим что там есть в Java.
Директива / Оператор using
Импорт типов
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
распространяется на текущий файл.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));
}
}
Wildcard Imports
Если мы пишем 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 и IDisposable
Как это работает?
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 можно объединить несколько объявлений одного типа
using (StringReader left = new StringReader(numbers),
right = new StringReader(letters)) { ... }
IDisposable Interface
Интерфейс для реализации освобождения неуправляемых ресурсов.
Стоит быть аккуратных, возможны проблемы если метод 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.
IAsyncDisposable Interface
Интерфейс для реализации асинхронного освобождения неуправляемых ресурсов.
А что там в Java?
Все немного похоже и немного другое чем в C#. Аналог для using директивы - это import. А для using оператора - это try-with-resources.
Р ассмотрим далее подробнее.
import как аналог using
Импортировать тип из другого пакета можно так
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);
Глобальный импорт как c global using
Нет.
Wildcard Imports
Такой подход в Java будем считать не самым лучшим выбором при написании кода, так как используя это:
import MyApplication.MyPackage.*;
мы можем неявно принести в нашу реализацию класс который мы бы не хотели импортировать.
Поэтому, в Java подход по умолчанию - это импорт только нужного типа вот так:
import MyApplication.MyPackage.MyClass;
try-with-resources
Как это работает?
В Java try (если он with-resources) умеет "закрывать" объекты. Совсем как using
в C#.
Мы можем использовать объект, реализующий интерфейс AutoCloseable
, как приведено ниже.
try
в этом случае, помимо своей обычной работы по контролю за исключениями, вызовет метод close()
для освобождения ресурсов в конце работы своего блока.
try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
writer.println("Hello World");
}
AutoCloseable Interface
Все как в 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.
Conclusion
Мне показалось что в C# с using
больше способов выстрелить себе в ногу. Возможно это из-за:
- wildcard imports для
using
в C# - это поведение по умолчанию - global using