Как происходит это общее наследование (внутренне)? - PullRequest
2 голосов
/ 13 июля 2009

Как вы думаете, следующий код? Это хорошо? Если так, то почему? Если нет, то почему это не так? А как CLR видит этот код?

public abstract class EntityBase<TEntity> : IEquatable<TEntity>
{        
    public bool Equals(TEntity other)
    {
        // check equalitiy
    }

    // yes, below is object's Equals and GetHashCode method implementation
}

public class Person : EntityBase<Person>
{
}

У меня немного странное чувство по этому поводу. Как проблема с курицей и яйцом. А вот код платформы .Net, который ведет себя так же.

public sealed class String : IComparable<string>, IEquatable<string> // I removed other interfaces

Есть мысли?

Ответы [ 4 ]

2 голосов
/ 13 июля 2009

При правильных обстоятельствах (например, реализация IComparable<T>) это именно то, что нужно делать.

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

С другой стороны, C ++ допускает «любопытно повторяющийся базовый шаблон»:

template<typename T>
class SomeWrapper<T> : T { ... ]

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

1 голос
/ 13 июля 2009

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

class Program
{
    static void Main(string[] args)
    {
        var wife = new Human(Gender.Female);
        var baby = wife.GiveBirth();
        Console.WriteLine(baby.Gender);

        Console.ReadKey();
    }
}

class CanGiveBirthTo<T> where T : new()
{
    public CanGiveBirthTo()
    {
    }

    public T GiveBirth()
    {
        return new T();
    }
}

class Human : CanGiveBirthTo<Human>
{
    public Gender Gender { get; private set; }

    public Human(Gender gender)
    {
        Gender = gender;
    }

    public Human()
    {
        Gender = RandomlyAssignAGender();
    }

    Gender RandomlyAssignAGender()
    {
        var rand = new Random();
        return (Gender) rand.Next(2);
    }
}

enum Gender
{
    Male = 0,
    Female = 1
}
0 голосов
/ 15 декабря 2009

Для справки других людей я скопировал ответ Эрика Липперта (который отвечает в комментарии).

Хотя определение появляется круговой, это не так. Тем не менее, C # Алгоритм обнаружения цикла компиляторов и неправильно и слабо. Неправильно потому что неправильно определяет нециклы как циклы, и слабый, потому что он не в состоянии обнаружить определенные очень неприятные циклы. Если эта тема вас интересует, смотрите мой статья об этом здесь: http://blogs.msdn.com/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx

0 голосов
/ 13 июля 2009

Я не вижу проблемы с вашим кодом. Почему это может быть проблемой?

Что касается внутреннего представления, то dotNet JIT компилирует класс для каждой общей версии. Итак, следующее:

class Foo<T> { public T Property; }
Foo<Int> fooint;
Foo<String> foostring;

Скомпилировано в:

class FooInt { public Int Property; } 
class FooString { public String Property; }
FooInt fooint;
FooString foostring;
// This is kept for if it is needed later.
// For example for generic casting, a C#4 feature.
class Foo<T> { public T Property; }
...