Интерфейсы C #: возможно ли ссылаться на тип, который реализует интерфейс внутри самого интерфейса? - PullRequest
5 голосов
/ 25 июля 2010

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

public interface ICoolInterface<T>
{
    T Value { get; set; }
    T DoSomethingCool();
}

public class CoolInt : ICoolInterface<int>
{
    private int _value;

    public CoolInt(int value)
    {
        _value = value;
    }

    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public int DoSomethingCool()
    {
        return _value * _value;
        // Ok, so that wasn't THAT cool
    }
}

И это все хорошо, но чтобы использовать CoolInt, мне нужно сделать что-то вроде этого:

CoolInt myCoolInt = new CoolInt(5);
int myInt = myCoolInt.Value;

Я бы предпочел, по крайней мере, с точки зрения назначения, что CoolInt работает так же, как int.Другими словами:

CoolInt myCoolInt = 5;
int myInt = myCoolInt;

Чтобы достичь этого, я добавил эти два оператора преобразования в свой класс CoolInt:

    public static implicit operator CoolInt(int val)
    {
        return new CoolInt(val);
    }

    public static implicit operator int(CoolInt obj)
    {
        return obj.Value;
    }

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

C # имеет много имен-заполнителей для вещей, которые неявно определены или еще не определены.T, который обычно используется в универсальном программировании, является одним из примеров.Я предполагаю, что ключевое слово value, используемое в свойствах, является другим.«Эту» ссылку можно считать другой.Я надеюсь, что есть еще один символ, который я могу использовать в своем интерфейсе для обозначения «типа класса, реализующего этот интерфейс», например «реализатор».

    public static implicit operator implementer(int val)
    {
        return new IntVal(val);
    }

    public static implicit operator int(implementer obj)
    {
        return obj.Value;
    }

Возможно ли это?

Ответы [ 5 ]

4 голосов
/ 25 июля 2010

Почему бы вам не создать абстрактный класс ? Таким образом, вы можете встроить некоторую функциональность «по умолчанию» в ваш класс.

2 голосов
/ 25 июля 2010

К сожалению, нет :(

C # плохо справляется с перегрузкой операторов (это один пример, другой - общие ограничения для определенных типов операторов).

0 голосов
/ 10 марта 2011

Было бы полезно, если, по крайней мере, для интерфейсов можно было бы объявить, что класс реализует интерфейс в терминах объекта;это было бы особенно здорово, если бы существовало ограничение универсального типа «interface».Тогда можно, например, сделать что-то вроде (синтаксис VB)

Class Foo(Of T as Interface)
  Implements T via Bar  ' Declares variable 'bar' of type T
  Sub DoSomething
    ' Does something
  End Sub
End Class

, а затем привести Foo (T) к T и заставить его вести себя как T. Может быть, кто-то из MS может наткнуться наидею и передать ее?

Следует отметить, кстати, хороший шаблон, похожий на ваш ICoolInterface:

public interface ISelf<T>
{
    T Self { get;}
}
public interface IFoozle
{
  ... definitions for IFoozle
}
public interface IFoozle<T> : ISelf<T> , IFoozle;
{
  /* Empty except for above declarations */
}
... similarly define IWoozle and IWoozle<T&gt etc.

Затем можно объявить поле, которое может реализовать IWoozle и IFoozle, инаследуется от BoozleBase (который не реализует ни один из них) через:

  IWoozle<IFoozle<BoozleBase>> myField1;
or
  IFoozle<IWoozle<BoozleBase>> myField2;

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

0 голосов
/ 25 июля 2010

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

        CoolInt x = (CoolInt)5;
        int j = x;

Достаточно близко?

    // Slightly sneaky, we pass both the wrapped class and the wrapping class as type parameters to the generic class
    // allowing it to create instances of either as necessary.

    public abstract class CoolClass<T, U>
        where U : CoolClass<T, U>, new()
    {
        public T Value { get; private set; }

        public abstract T DoSomethingCool();

        // Non-public constructor
        protected CoolClass()
        {
        }

        public CoolClass(T value)
        {
            Value = value;
        }

        public static implicit operator CoolClass<T, U>(T val)
        {
            return new U() { Value = val};
        }

        public static implicit operator T(CoolClass<T, U> obj)
        {
            return obj.Value;
        }

    }

    public class CoolInt : CoolClass<int, CoolInt>
    {
        public CoolInt()
        { 
        }

        public CoolInt(int val)
            : base(val)
        {
        }

        public override int DoSomethingCool()
        {
            return this.Value * this.Value; // Ok, so that wasn't THAT cool
        }
    }
0 голосов
/ 25 июля 2010

Почему бы не использовать вместо этого методы расширения? Это позволяет вам «добавлять» методы в int, не используя другой тип.

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