2008-10-20 4 views
5

У меня есть класс, содержащий кучу свойств. Это ошибка программиста, если они вызывают ToString() на объекте этого типа. Возьмите этот пример код:C#: Ошибка компилятора команды при использовании myObj.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 так, что она возвращает идентификатор. Однако я считаю, что это плохая практика, потому что программисты «случайно» получат рабочий код. Программист, использующий мой класс, должен указать, что они хотят.

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

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

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

ответ

20

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

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

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

+0

Ehh ... это, вероятно, менее «хакерское», чем переопределение ToString() с неправильным возвратом. – EBGreen 2008-10-20 15:45:14

+1

Он работает, по крайней мере. Возможно, .NET-пользователям необходимо добавить атрибут «IToldYouNeverToCallMe». – MusiGenesis 2008-10-20 16:10:12

+0

Это работает, и это решение, с которым я столкнулся, если Джейсон Джексон не станет хорошей причиной, почему я не должен. – 2008-10-20 16:14:28

1

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

44

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

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

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

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

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

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

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

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

1

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

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

7

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

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

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

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

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

 Foo myObj = new Foo(); 

     Console.WriteLine(myObj); 

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

Предложение по проблеме ловли во время компиляции: Я понял, что ранее не предлагал решение для решения этой проблемы. Я действительно не знаю, в каком формате находится ваш идентификатор, поэтому я только предполагаю, что он является int, но почему бы не защитить все, что создает URL-адрес с помощью querystring, и передать id как 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); 
0

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

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

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

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

7

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

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

public new void ToString() { } 

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

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

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

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

Смежные вопросы