Дженерики с общими параметрами и абстрактным классом

У меня есть два базовых класса. Второй родовой класс имеет ограничение на его параметр первого класса.

abstract class FirstClass<T> {...}

abstract class SecondClass<U> where U : FirstClass {...}

Это не работает, потому что FirstClass не определен. Поэтому мне нужно это сделать.

abstract class FirstClass<T> {...}

abstract class SecondClass<U, T> where U : FirstClass<T> {...}

Что работает. Тем не менее, это делает выполнение этих абстрактных классов уродливым.

class SomeClass {...}

class MyFirstClass : FirstClass<SomeClass> {...}

class MySecondClass : SecondClass<MyFirstClass, SomeClass> {...}

Это кажется излишним для меня, потому что я задаю SomeClass дважды. Есть ли способ объявить его таким образом, что T из FirstClass автоматически является U для SecondClass. Мне бы хотелось, чтобы это выглядело так.

class SomeClass {...}

class MyFirstClass : FirstClass<SomeClass> {...}

class MySecondClass : SecondClass<MyFirstClass> {...}

Хотя я сомневаюсь, что этот точный сценарий возможен, есть ли более чистая, что делать, что я пытаюсь сделать?

Изменить

Несколько человек предложили создать интерфейс IFirstClass. Но мои определения ближе к этому.

class FirstClass<T>
{
    public T MyObj { get; set; }
}

class SecondClass<U, T> where U : FirstClass<T>
{
    U MyFirstClass { get; set; }
}

С интерфейсом я не могу получить доступ к MyFirstClass.MyObj из SecondClass. Хотя я мог бы создать объект T MyObj {get; задавать; } на IFirstClass, затем используйте new, чтобы скрыть его, silverlight выдает подгонку в привязку, если я это сделаю.

Ответы

Ответ 1

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

Ответ 2

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

interface IFirstClass {...}

abstract class FirstClass<T> : IFirstClass {...}

abstract class SecondClass<T> where T : IFirstClass {...}

Ответ 3

Создайте интерфейс, который реализует FirstClass. Затем вы можете ограничить SecondClass интерфейсом.

Ответ 4

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

Вы можете объявить несколько интерфейсов с определенным типом идентификатора. Не идеальное решение, но упрощает объявление классов сущностей.

public interface IIntPersistentEntityService<TPersistentEntity>
        : IPersistentEntityService<TPersistentEntity, int>
    where TPersistentEntity : IPersistentEntity<int>
{
}

public interface IStringPersistentEntityService<TPersistentEntity>
        : IPersistentEntityService<TPersistentEntity, string>
    where TPersistentEntity : IPersistentEntity<string>
{
}

Тогда класс User может быть объявлен так:

public class UserService : IIntPersistentEntityService<User>
{
    public User Get(int id)
    {
        throw new NotImplementedException();
    }
}

Вы получите ошибку компилятора, если у вас нет соответствующего типа Id.