C #: принудительная ошибка компилятора при использовании myObj.ToString () - PullRequest
5 голосов
/ 20 октября 2008

У меня есть класс, который содержит множество свойств. Программист ошибается, если он вызывает ToString () для объекта этого типа. Возьмите этот пример кода:

using System;

public class Foo
{
    public int ID = 123;
    public string Name = "SomeName";

    private string ToString() { return null; }
}

public class MyClass
{
    public static void Main()
    {
        Foo myObj = new Foo();
        WL("I want this to be a compiler error: {0}", myObj.ToString());
        RL();
    }

    #region Helper methods

    private static void WL(object text, params object[] args)
    {
        Console.WriteLine(text.ToString(), args);   
    }

    private static void RL()
    {
        Console.ReadLine(); 
    }

    #endregion
}

Вы могли бы рассуждать, что если ID - это то, что большинство людей хотят записать в виде строки, то я должен реализовать ToString, чтобы он возвращал ID. Тем не менее, я считаю, что это плохая практика, потому что программисты «случайно» получат рабочий код. Программист, использующий мой класс, должен указать, что он хочет.

Вместо этого я хотел бы, чтобы кто-то вызывал myObj.ToString (), чтобы это отображалось как ошибка времени компиляции. Я думал, что смогу сделать это, создав частную функцию ToString (), но это не сработает.

Причина, по которой я это поднял, заключается в том, что мы получили строку запроса, которая содержала полное имя класса, а не идентификатор.

Итак, вопрос такой: Есть ли способ "скрыть" функцию ToString (), чтобы ее вызов на объекте моего класса вызывал ошибку компилятора?

Ответы [ 7 ]

45 голосов
/ 20 октября 2008

Я не могу не подчеркнуть, насколько плоха идея этого дизайна.

ToString() является частью объекта договора в .Net. Если вы не хотите его реализовывать, не переопределяйте его и просто дайте ему вернуть информацию о типе. Какой вред это может нанести?

Я не хочу быть таким негативным, но я абсолютно обескуражен, что кто-то захочет избавиться от ToString().

Некоторые дополнительные очки:

  1. Почему программисты, использующие этот класс, предполагают, что ToString() вернет идентификатор? Делают ли это другие классы в вашей экосистеме? Можно утверждать, что ToString() должен возвращать некоторые значимые данные. Но вы действительно не должны программировать против результатов вызова ToString(). ToString() для строковых представлений класса, точка. Это звучит как проблема образования или коммуникации между программистами или отделами.

  2. Нанесение вреда ToString() любым способом, независимо от того, сможете ли вы выяснить, как во время компиляции или сгенерировать исключение во время выполнения, будет иметь место рябь. Я никогда не видел, как это делается, и не ожидал, что какой-либо класс, который я использую, продемонстрирует это поведение. Я думаю, что большинство программистов будут иметь такие же ожидания. Будут ли этого ожидать будущие программисты, использующие ваш класс? Какие ошибки и технические кошмары вы вызываете в будущем?

  3. Как это влияет на IDE или отладчик, которые зависят от ToString()?

  4. Какое влияние это окажет при использовании технологий привязки данных, которые не привязываются к определенному типу, но используют отражение во время выполнения для извлечения значений? Большая часть привязки данных будет вынуждена вызывать ToString() для объекта, если не указан член для использования.

20 голосов
/ 20 октября 2008

Устаревший атрибут позволяет вам сделать это.

[Obsolete("Use the XYZ properties instead of .ToString() on Foobar", true)]

Логическое значение в конце указывает, должна ли компилятор считать использование этого элемента ошибкой.

7 голосов
/ 21 октября 2008

Я бы выбрал гибридный подход. (Эй, разве это не так, чтобы прочесывать другие ответы? :))

Сначала создайте новую ToString, которая возвращает void. Отсутствие возвращаемого значения означает, что они не могут использовать его для получения какого-либо случайно красивого кода:

public new void ToString() { }

Затем добавьте атрибут «Устаревший», чтобы, когда люди действительно его вызывают, они получали предупреждение о том, что ToString плох.

Вам не нужно переопределять ToString таким образом, просто скройте его с чем-то бесполезным. Тот факт, что он не имеет возврата, нарушает весь код, что приводит к ошибке компилятора в верхней части устаревшего сообщения.

Люди, обращающиеся к Объекту, не являются вашей заботой, если я понимаю ваш вопрос напрямую. Вы не хотите, чтобы люди не вызывали ToString и не получали информацию о типе, вы хотите, чтобы они не думали, что ToString дает полезный результат.

Редактировать: Пожалуйста, не бросайте исключение и не переопределяйте ToString. Это может вызвать «плохие вещи», когда ваш объект рассматривается как объект. Простое использование «new» позволяет получить преимущества, о которых вы просили, без использования других фреймворков.

7 голосов
/ 20 октября 2008

Я совершенно не согласен с использованием свойства устаревшего для этого по нескольким причинам.

Для начала у вас будет предупреждение о методе ToString (), который вы переопределили и пометили свойством устаревшего:

    [Obsolete("dont' use", true)]
    public override string ToString()
    {
        throw new Exception("don't use");
    }

выдает это предупреждение: Предупреждение 1 Устаревший член ClassLibrary1.Foo.ToString () переопределяет устаревший член object.ToString () d: \ source \ ClassLibrary1 \ ClassLibrary1 \ Class1.cs 11 32 ClassLibrary1

так что теперь вы застряли с постоянным предупреждением в вашем коде. Кроме того, это не совсем решит вашу проблему. Что происходит, когда что-то в структуре неявно вызывает ToString () сейчас? Результатом следующего кода является то, что код в теле ToString () по-прежнему вызывается:

        Foo myObj = new Foo();

        Console.WriteLine(myObj);

Так что теперь у вас есть предупреждение в вашем коде, и оно не мешает разработчику делать то же самое снова и снова. Я думаю, что правильным шагом здесь является попытка найти способ вызвать соответствующее исключение во время выполнения, а не пытаться связываться с объектными контрактами .net.

Предложение по отлову проблемы во время компиляции: Я понял, что ранее не предлагал решения этой проблемы. Я действительно не знаю, в каком формате ваш идентификатор, наверняка, поэтому я только догадываюсь, что это int, но почему бы не защитить то, что создает URL с помощью строки запроса, и передать идентификатор как int. Таким образом, разработчик не может случайно передать какую-то бессмысленную строку без ошибки компиляции. Вот так например:

public string CreateItemUrl(int itemId)
{
   return string.Format("someurl.aspx?id={0}", itemId);
}

Теперь, позвонив по этому номеру:

CreateItemUrl(myObj.Id);

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

string theUrl = string.Format("someurl.aspx?id={0}", myObj);
1 голос
/ 20 октября 2008

Переопределите ToString для возврата string.Empty, тогда вы не добавили бы ничего к строке запроса. По умолчанию, если вы не переопределите ToString, вы получите версию Object, которая возвращает this.GetType (), который даст вам что-то вроде пространства имен и имени класса.

Вызов ToString кажется довольно разумным, я бы не хотел вызывать ошибки компилятора для того, кто это делает.

1 голос
/ 20 октября 2008

Используйте ключевое слово override с общедоступной функцией ToString (), чтобы переопределить метод System.Object ToString ().

0 голосов
/ 20 октября 2008

Пожалуйста, примите во внимание ваш дизайн / мнение, которое будет изменено:)

Прежде всего, определение Foo.ToString определяет не переопределение для Object.ToString (), а новое и должно начинаться с префикса с ключевым словом «new» во избежание неправильного понимания семантики. Или явно объявить «переопределить». ИМХО, компилятор выдает соответствующее предупреждение.

Даже если вы найдете способ запретить вызов Foo.ToString, он будет запрещен во время компиляции только тогда, когда известно, что тип «this» является Foo или его потомком, но ((объект) foo). ToString () будет правильным решением , потому что ToString является методом интерфейса Object.

Кроме того, предотвращение вызова ToString нежелательно, поскольку отладчик использует его для представления значения. SY, Джейк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...