Принудительно использовать подклассы интерфейса для реализации ToString - PullRequest
56 голосов
/ 04 февраля 2009

Допустим, у меня есть интерфейс IFoo, и я хочу, чтобы все подклассы IFoo переопределяли метод ToString объекта. Это возможно?

Простое добавление сигнатуры метода в IFoo как таковое не работает:

interface IFoo
{
    String ToString();
}

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

Ответы [ 7 ]

81 голосов
/ 04 февраля 2009

Я не верю, что вы можете сделать это с помощью интерфейса. Вы можете использовать абстрактный базовый класс, хотя:

public abstract class Base
{
    public abstract override string ToString(); 
}
21 голосов
/ 04 февраля 2009
abstract class Foo
{
    public override abstract string ToString();
}

class Bar : Foo
{
    // need to override ToString()
}
8 голосов
/ 06 июня 2009

Jon & Andrew: этот абстрактный трюк действительно полезен; Я понятия не имел, что вы можете закончить цепочку, объявив ее абстрактной. Приветствия:)

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

public abstract class BaseClass
{
    public abstract string ToStringImpl();

    public override string ToString()
    {
        return ToStringImpl();
    }    
}
1 голос
/ 04 августа 2011

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

Я использую гибрид предложенных Марком и Эндрю решений.

В моем приложении все доменные сущности происходят от абстрактного базового класса:

public abstract class Entity
{
    /// <summary>
    /// Returns a <see cref="System.String"/> that represents this instance.
    /// </summary>
    public override string ToString()
    {
        return this is IHasDescription
                   ? ((IHasDescription) this).EntityDescription
                   : base.ToString();
    }
}

Сам интерфейс определяет только простой метод доступа:

public interface IHasDescription : IEntity
{
    /// <summary>
    /// Creates a description (in english) of the Entity.
    /// </summary>
    string EntityDescription { get; }
}

Итак, теперь есть встроенный резервный механизм - или, другими словами, Entity, который реализует IHasDescription, должен обеспечивать EntityDescription, но любой Entity все еще может преобразовывать в строку.

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

ИМХО, интерфейсы, которые реализуются базовым классом object, не должны "считаться" как реализованные - было бы неплохо иметь для этого опцию компилятора, но, ну да ладно ...

1 голос
/ 04 февраля 2009

Реализация метода интерфейса неявно запечатывает метод (а также переопределяет его). Итак, если вы не укажете обратное, первая реализация интерфейса завершает цепочку переопределения в C #.

Essential .NET

Абстрактный класс = твой друг

Проверьте этот вопрос

0 голосов
/ 19 июня 2018

Извините, что похоронил эту старую нить из могилы, тем более что наш дорогой @ jon-skeet уже дал свой ответ .

Но если вы хотите сохранить интерфейс и не использовать абстрактный класс, я думаю, это все еще возможно, если ваш интерфейс реализует интерфейс System.IFormattable .

interface IFoo : IFormattable
{
}

Единственное, что нужно иметь в виду, чтобы правильно реализовать этот IFormattable, конкретная реализация также должна перезаписать Object.ToString().

Это ясно объяснено в этом хорошем посте.

Ваш конкретный класс теперь похож на

public class Bar : IFoo
{
    public string ToString(string format, IFormatProvider formatProvider)
    {
        return $"{nameof(Bar)}";
    }

    public override string ToString()
    {
        return ToString(null, System.Globalization.CultureInfo.CurrentCulture);
    }
}

Надеюсь, это еще может кому-нибудь помочь.

0 голосов
/ 04 февраля 2009

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

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