2016-06-07 5 views
3

Я видел C# класс SomeClass, который был определен какКак класс может наследовать от параметризованной версии самого себя?

public class SomeClass : IComparable<SomeClass>, IEquatable<SomeClass> 
{ 
    // ... 
} 

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

+2

Это просто означает, что 'SomeClass' будет реализовывать методы' IComparable' и 'IEquatable', которые используют' SomeClass' как тип в своей сигнатуре. В частности, 'int CompareTo (SomeClass)' и 'bool Equals (SomeClass)' – juharr

+0

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – sstan

ответ

6

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

Например, IComparable<T> говорит, что в качестве параметра будет использоваться метод CompareTo(), который принимает объект типа T. Таким образом, за счет внедрения IComparable<SomeClass> вы просто гарантировать, что метод с этой подписи будет существовать в этом классе:

public class SomeClass : IComparable<SomeClass> 
{ 
    public int CompareTo(SomeClass other) 
    { 
     //... 
    } 
} 

И да, это довольно распространенная практика. Классы часто реализуют общие интерфейсы IComparable<> и IEquatable<>, чтобы показать, что их можно сравнить с другими элементами того же типа. Возможно, стоит также упомянуть, что перечисления на Java объявлены как расширение Enum<> самих себя - шаблон, который не является общим в C#, но время от времени появляется.

+0

Я не вижу, как это «ключ» вообще. Совершенно правильно наследовать параметризованную версию себя, рассмотрите следующее: 'class Foo {public T Value; } class Foo: Foo {} 'Я бы сказал, что ключ понимает, что' Foo' и 'Foo ' являются * не теми же типами *, и поэтому их наследование eachother (хотя и не в то же время) не странно вообще. – kai

+1

@kai: 'class Foo: Foo ' не является примером класса, наследующего от себя. Как вы говорите, это два разных типа. Если у вас есть 'class Foo : Foo ', то он будет пытаться наследовать от себя, и что * не будет иметь смысла, поэтому проблема OP является действительной. Следовательно, ключ должен признать, что 'IComparable ' не совпадает с 'SomeClass'. Другими словами, он не наследует или не реализует сам себя, а другой тип целиком - он просто переходит в качестве общего параметра к этому другому типу в этом случае. – StriplingWarrior

+0

О чем говорит OP, была «параметризованная версия самого себя» *, не могли бы вы описать 'IEnumerable ' как «параметризованную версию» 'IEnumerable'? – kai

0

Это не Inheriting, он реализует IComparable Interface. что происходит

Someclass Внедряет Icomparable и интерфейс IEquatable. Реализация интерфейса подобна подписанию контракта, в котором говорится, что вы gaurentee, что этот класс будет реализовывать методы на интерфейсе.

Icomparable msdn, IEquatable. Если вы посмотрите на страницы MSDN, вы увидите, что SomeClass gaurentees реализует методы в некотором роде.

Это очень распространенная практика, и это разные имена. Наиболее я слышу programming by contract и Implementation over Inhertience. Это позволяет вам делать много классных вещей, таких как Injection Dependency, правильное тестирование модулей, лучшие дженерики. Он делает это, потому что компилятор не должен знать конкретный класс, который реализует ваш объект. Просто нужно знать, что на нем есть определенные функции. Для дальнейшего чтения об этом я бы прочитал главу первой из группы из четырех шаблонов шаблонов дизайна.

Wikipedia link В частности, введение в главе одной секции

+1

Это и не отвечает на вопрос, и аргументирует семантику: интерфейс на C# - это просто строгая форма абстрактного класса с абстрактными членами и без государства. Использование слова «реализует» вместо «наследует» на самом деле не объясняет и не изменяет ничего. – kai

+1

@kai Я думаю, что вы совершенно ошибаетесь в своем утверждении «Использование слова« реализует »вместо« наследует »на самом деле не объясняет и не изменяет ничего». Говоря вещь X реализует Y - это стандарт дефакто. Например, https://msdn.microsoft.com/en-us/library/ms173156.aspx, это тот же самый глагол, который использует Microsoft при использовании интерфейса. – gh9

+0

Я знаю, что это стандартный жаргон, но это не принципиально другое. реализация - это всего лишь строгая форма наследования, они имеют одинаковую семантику и эффекты. Единственная разница заключается в том, что класс может наследовать от нескольких интерфейсов, но только от одного класса. И это все еще не связано с вопросом. – kai

0

Код, который вы отправили, не наследуется ни от одного класса. Он реализует некоторые так называемые интерфейсы. Как перевести этот фрагмент: «Я гарантирую, что SomeClass будет сравнимым и равнозначным с другими экземплярами SomeClass. Я дам определения в этом классе о том, как это сделать».

О специализирующаяся класса из другого класса ... Что вы можете сделать что-то вроде этого:

using System; 
using System.Collections.Generic; 

namespace ConsoleApp1 
{ 
    class Pet 
    { 
     protected string name; 
     public Pet(String name) 
     { 
      this.name = name; 
     } 

    } 

    class Dog : Pet 
    { 
     private List<String> tricks; 
     public Dog(String name, List<String> tricks):base(name) 
     { 
      this.tricks = tricks; 
     } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<string> tricks = new List<string>(); 
      tricks.Add("sit"); 
      tricks.Add("jump"); 
      tricks.Add("bark"); 
      Dog puppy = new Dog("Fido", tricks); 
     } 
    } 
} 

собака наследует от Pet. Собака вызывает конструктор Петра при создании. Независимо от имени, которое вы передаете в конструктор Dog, он отправит его в конструктор Pet. Поскольку происходит то, что подкласс сначала вызывает конструктор своего суперкласса с соответствующими аргументами. Затем он запускает собственный конструктор. Все, что объявлено публичным или защищенным в классе, будет видимым для его подклассов.

Поэтому собака будет иметь имя, а также список трюков:

puppy object result

Вы достичь такой точки зрения с окном «Locals».

Я рекомендую вам прочитать некоторые учебники по C# inheritance, interfaces и generics

0

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

В типах C# может быть общий над категориями других типов. Родовые типы - это в основном «конструкторы типов». Они берут другие типы в качестве параметров и используют их для построения новых типов. Например, IEnumerable<int> и IEnumerable<string>: два совершенно разных типа. Неоригинальная версия (IEnumerable) является третьей. В C# тип A может наследовать любой другой тип B, пока ни один из следующих не верно (я надеюсь, что я ничего не пропустил):

  • B уже подтип A
  • B является класс и а уже унаследовал еще один класс
  • B является структурой
  • а представляет собой интерфейс, но в не
  • а тот же тип, как B
  • запечатан
  • Б
  • А является структура и B не является интерфейсом

Это даже делает следующий код правовой:

class Foo<T> 
{ 
    public T Value; 
} 

class Foo : Foo<int> 
{ 
} 

Foo и Foo<T> различные типы, так что нет никаких проблем для одного наследуйте Другие.

Вы можете прочитать больше о воспроизведенных здесь:

https://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx

А про наследование здесь:

https://msdn.microsoft.com/en-us/library/ms173149.aspx

1

Переведенный в "английском", это означает: «Мальчик (или девушка), вам лучше быть безопасным по типу при реализации этих интерфейсов, особенно IComparable. В противном случае вам нужно будет выполнить кастинг типов, который, я думаю, вы не хотите «

Посмотрите на код ниже. SomeClass реализован IComparable и IComparable. См. Различия между реализациями CompareTo (object) и CompareTo (SomeClass).

namespace InterfacesStuff 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      var someClass1 = new SomeClass {ComparedValue = 1}; 
      var someClass2 = new SomeClass {ComparedValue = 2}; 

      //someClassObject defined as SomeClass 
      //object someClassObject = new SomeClass { ComparedValue = 2 }; 

      //someClassObject defined as anything else but SomeClass 
      object someClassObject = 5; 

      int comparisonSomeClassBySomeClass = someClass1.CompareTo(someClass2); 

      int comparisonSomeClassByObject = someClass1.CompareTo(someClassObject); 
     } 
    } 


    public class SomeClass : IComparable, IComparable<SomeClass>, IEquatable<string>, IEquatable<int>, 
     IEquatable<double> 
    { 
     public int ComparedValue; 

     public int CompareTo(object obj) 
     { 
      var presumedSomeClassObject = obj as SomeClass; 

      if (presumedSomeClassObject != null) 
      { 
       if (ComparedValue <= ((SomeClass) obj).ComparedValue) 
        return -1; 
      } 

      return 0; 
     } 

     public int CompareTo(SomeClass other) 
     { 
      if (ComparedValue <= other.ComparedValue) 
       return -1; 

      return 0; 
     } 

     public bool Equals(double other) 
     { 
      throw new NotImplementedException(); 
     } 

     public bool Equals(int other) 
     { 
      throw new NotImplementedException(); 
     } 

     public bool Equals(string other) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 
Смежные вопросы