Как принудительно использовать возвращаемое значение метода в C #?

У меня есть часть программного обеспечения, написанного с плавным синтаксисом. Метод цепочка имеет окончательный "конец", до которого в коде фактически не делается ничего полезного (подумайте о NBuilder или Linq-to-SQL ' генерация запросов фактически не попадает в базу данных, пока мы не перебираем наши объекты, скажем, с помощью ToList ()).

Проблема, с которой я столкнулся, состоит в том, что другие разработчики не понимают, как правильно использовать код. Они пренебрегают вызовом "конечного" метода (таким образом, фактически никогда не "ничего не делают")!

Меня интересует принудительное использование возвращаемого значения некоторых из моих методов, чтобы мы никогда не могли «завершить цепочку», не вызывая тот метод «Finalize ()» или «Save ()», который фактически выполняет работу.

Рассмотрим следующий код:

//The "factory" class the user will be dealing with
public class FluentClass
{
    //The entry point for this software
    public IntermediateClass Init()
    {
        return new IntermediateClass();
    }
}

//The class that actually does the work
public class IntermediateClass
{
    private List _values;

    //The user cannot call this constructor
    internal IntermediateClass()
    {
        _values = new List();
    }

    //Once generated, they can call "setup" methods such as this
    public IntermediateClass With(T value)
    {
        var instance = new IntermediateClass() { _values = _values };
        instance._values.Add(value);
        return instance;
    }

    //Picture "lazy loading" - you have to call this method to
    //actually do anything worthwhile
    public void Save()
    {
        var itemCount = _values.Count();
        . . . //save to database, write a log, do some real work
    }
}

Как видите, правильное использование этого кода было бы чем-то например:

new FluentClass().Init().With(-1).With(300).With(42).Save();

Проблема в том, что люди используют его таким образом (думая, что он достигает того же, что и выше):

new FluentClass().Init().With(-1).With(300).With(42);

Эта проблема настолько распространена, что при исключительно хороших намерениях, другой разработчик однажды фактически изменил имя метода «Init», чтобы указать, что ЭТОТ метод выполняет «реальную работу» программного обеспечения.

Подобные логические ошибки очень трудно обнаружить, и, конечно же, они компилируются, потому что вполне приемлемо вызвать метод с возвращаемым значением и просто «притвориться», что он возвращает void. Visual Studio все равно, если вы это сделаете; ваше программное обеспечение по-прежнему будет компилироваться и запускаться (хотя в некоторых случаях я считаю, что оно выдает предупреждение). Конечно, это отличная возможность. Представьте себе простой метод InsertToDatabase, который возвращает идентификатор новой строки в виде целого числа - легко увидеть, что в некоторых случаях нам нужен этот идентификатор, а в некоторых случаях мы могли бы обойтись без него.

случай этого программного обеспечения, Нет никаких причин отказываться от этой функции «Сохранить» в конце цепочки методов. Это очень специализированная утилита, и единственная выгода - от последнего шага.

Я хочу, чтобы чье-то программное обеспечение завершалось с ошибкой на уровне компилятора , если они вызывают «With ()», а не «Save ()» ".

Это кажется невыполнимой задачей традиционными средствами - но именно поэтому я прихожу к вам, ребята. Есть ли атрибут, который я могу использовать для предотвращения "преобразования метода в void" или чего-то подобного?

Примечание: Альтернативный способ достижения этой цели, который мне уже предлагали, - это написание набора единиц тесты для обеспечения соблюдения этого правила и использование чего-то вроде http://www.testdriven.net для привязки их к компилятору. Это приемлемое решение, но я надеюсь на что-то более элегантное.

10
задан Bokonon 23 March 2011 в 20:05
поделиться