C# использование оператора с возвращаемым значением или встроенная объявленная переменная результата
Мне интересно, есть ли какой-нибудь способ оптимизировать оператор using для объявления и назначения выходных данных вместе (когда это одно значение).
Например, что-то похожее на новый способ встроенного объявления объявленной переменной параметра out.
//What I am currently doing:
string myResult;
using(var disposableInstance = new myDisposableType()){
myResult = disposableInstance.GetResult();
}
//That would be ideal
var myResult = using(var disposableInstance = new myDisposableType()){
return disposableInstance.GetResult();
}
//That would be great too
using(var disposableInstance = new myDisposableType(), out var myResult){
myResult = disposableInstance.GetResult();
}
Спасибо за ваш вклад.
4 ответа
Вы можете использовать метод расширения, чтобы "упростить" этот шаблон использования:
public static class Extensions {
public static TResult GetThenDispose<TDisposable, TResult>(
this TDisposable d,
Func<TDisposable, TResult> func)
where TDisposable : IDisposable {
using (d) {
return func(d);
}
}
}
Тогда вы используете это так:
string myResult = new myDisposableType().GetThenDispose(c => c.GetResult());
Нет, такого ярлыка нет. Ваш оригинальный путь правильный.
Вы могли бы обернуть это в функцию, если вы делаете это достаточно часто
public class Utilities
{
public static TReturn GetValueFromUsing<T,TReturn>(Func<T,TReturn> func) where T : IDisposable, new()
{
TReturn result = default(TReturn)
using(var instance = new T())
result = func(instance);
return result;
}
}
использование
var result = Utilities.GetValueFromUsing<myDisposableType,string>(x => x.GetResult());
Но человек был бы излишним.
Это забавно, потому что я начал читать функциональное программирование на C# пару дней назад, и один из первых примеров выглядит следующим образом:
public static TResult Using<TDisposable, TResult>(TDisposable disposable, Func<TDisposable, TResult> func)
where TDisposable : IDisposable
{
using (disposable)
{
return func(disposable);
}
}
Использование:
var result = Using(new DbConnection(), x => x.GetResult());
Обратите внимание, что, в отличие от других опубликованных ответов, эта функция не несет никакой ответственности, кроме как получить результат func
, невзирая на TDisposable
,
using
Инструкция не может быть использована в качестве r-значения, и поэтому нет способа присвоить ей значение.
Однако есть особый случай, и вы можете использовать его там, где это удобно: вы можете вернуть результат изнутри using
блок.
int F(int arg)
{
using (disposable = GetObj())
{
return disposable.Calculate(arg);
}
}
Эта форма часто сообщает о цели лучше, чем назначение локальной переменной. Вы даже можете превратить его в метод шаблона, где метод будет применять using
построить, а затем вызвать стратегию и вернуть ее результат.
class Useful<TDisposable> where TDisposable : IDisposable
{
private Func<TDisposable> Factory { get; }
public Useful(Func<TDisposable> factory)
{
this.Fatory = factory;
}
public TResult SafeDo<TResult>(Func<TDisposable, TResult> operation)
{
using (TDisposable obj = this.Factory())
{
return operation(obj);
}
}
}
Этот класс полностью пригоден для повторного использования, и его единственной обязанностью является обеспечение утилизации одноразовых компонентов. Вместо того, чтобы работать непосредственно с одноразовым классом, вы можете обернуть его в этот класс-обертку и использовать его таким образом, и у вас будет строгий пожизненный контроль над одноразовыми объектами:
void Worker(Useful<MyDisposableClass> wrapper)
{
int arg = 5;
wrapper.SafeDo(disp => disp.Calculate(arg);
}
В этом фрагменте кода disp
объект будет построен и расположен правильно. Конкретный аргумент, который потребовался бы для операции arg
берется из закрытия.