Использует ли преимущество опциональных крайних вариантов параметров для принудительной реализации ToString через злоупотребление интерфейсом языка? - PullRequest
7 голосов
/ 25 октября 2011

У меня есть интерфейс IKey, который я хочу иметь метод, который будет возвращать ключ в виде строки.Мы рассмотрели метод, подобный следующему:

String GetAsString();

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

public interface IKey
{
    string ToString(string dummyParameter=null);
}

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

Inреализации, которые мы можем просто игнорировать dummyParameter и возвращать то, что мы хотим, в безопасности, зная, что вызов ToString() всегда на самом деле вызовет ToString(null).

Теперь мне кажется, что это неправильно, но вв то же время в нем есть что-то очень приятное.Это почти то же самое, что и метод GetAsString(), так как его можно вызывать только на интерфейсе IKey и производных классах, за исключением того, что он выглядит как более естественный метод ToString(), который мы хотим использовать и который мы можемзаставить реализацию в дочернем классе.

Сказав, что фиктивный параметр, который не используется, кажется неправильным.

Так это ужасно?Или отлично?

И подходит ли этот вопрос для SO или он должен быть для программистов?

Примеры

public class Key :IKey 
    { 
        public string ToString(string abc = null) 
        { 
            return "100"; 
        } 
    }

Key key = new Key ();
Trace.WriteLine (key.ToString());
Trace.WriteLine (key.ToString(null));
Trace.WriteLine (key.ToString("ac"));
Trace.WriteLine (((object)key).ToString());

output:

100
100
100
Blah.Tests.Key

Ответы [ 7 ]

5 голосов
/ 25 октября 2011

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

abstract class X
{
    public abstract override string ToString();
}
1 голос
/ 25 октября 2011

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

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

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

Я не думаю, что это было бы "более естественным", чем метод / свойство с хорошим именем, которое еще не является членом object.

1 голос
/ 25 октября 2011

Я бы назвал это злоупотребление из-за проблемы, на которую вы намекаете прямо здесь:

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

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

IKey someKey = ...;
string keyAsString = someKey.ToString();
object someKeyAsObject = (object)someKey;
string keyAsString2 = someKeyAsObject.ToString();

Любой, кто просматривает этот код, предположит, чтоkeyAsString и keyAsString2 одинаковы.Однако это вызовет разные методы, которые могут иметь другое поведение.Ик!

1 голос
/ 25 октября 2011

перепрофилирование

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

Ответ заключается в том, чтобы иметь свой собственный отдельный метод, первоначальную идею. Все остальное означает, что вся документация .NET о ToString() становится «неправильной».

например. свойство Tag является объектом во многих элементах управления пользовательского интерфейса. Возможно, вы захотите «пометить» элементы управления в некоторой галерее элементов управления. То, что имя подходит, а тип подходит, не означает, что значение одно и то же, и вы можете схватить его и переопределить.

Нейминг

Я бы также предложил рассмотреть возможность изменения имени вашего интерфейса; разве реализаторы являются на самом деле ключами? У меня складывается впечатление, что они просто «включены» или имеют какой-то ключ, связанный с ними. В этом случае IKeyed, IIndexed или что-то может быть лучше. Тогда string Key { get; } становится более привлекательным. Возможно, проблема заключается только в наименовании .?

1 голос
/ 25 октября 2011

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

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

void Main()
{   
    Console.WriteLine(new Key().ToString());
}

public interface IKey 
{
    string ToString(string dummy = null);
}

class Key : IKey 
{   
    public string ToString(string dummy) 
    {
        return "myspecialKey";
    }
}

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

1 голос
/ 25 октября 2011

С моей точки зрения, такой ToString() метод в пользовательском интерфейсе немного испортил вещи, потому что пользовательский интерфейс показал метод со стандартным и хорошо известным именем ToString().

Я предпочитаю что-то более простое иочевидно, как:

string KeyText { get; }

ИЛИ метод

string ConvertKeyToString();
0 голосов
/ 21 марта 2012

только что с этим сталкивался.Как насчет того, чтобы интерфейс наследовал IFormattable?

http://msdn.microsoft.com/en-us/library/system.iformattable.aspx

Я сам этого не делал, поэтому могу ошибаться, но, похоже, это позволяет использовать параметр формата для ToString метод для вашего интерфейса.Обратите внимание, что вы по-прежнему не изменяете ToString без параметров, что, я согласен, не следует делать в интерфейсе, но вместо этого вы используете ToString(string format, IFormatProvider provider) с распознаваемым вводом формата, который в основном означает «дайте мне описание этого объекта»в контексте того, что он реализует IWhothing ».Очевидно, что каждый реализованный класс должен будет кодировать метод, но это только правильно.

...