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 берется из закрытия.

Другие вопросы по тегам