Дженерики с общими параметрами и абстрактным классом
У меня есть два базовых класса. Второй родовой класс имеет ограничение на его параметр первого класса.
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.