Можно ли реализовать этот интерфейс в целом, чтобы ему можно было передать только один параметр типа? - PullRequest
5 голосов
/ 01 декабря 2011

У меня есть интерфейс с именем Identifiable<TId>, который содержит один идентификатор свойства данного типа. Я хочу создать универсальный класс, который принимает один из них в качестве параметра типа. Он должен быть универсальным, потому что я хочу вернуть конкретный тип, вызвать из него другие универсальные методы и использовать такие вещи, как typeof(T).

Это прекрасно работает:

public class ClassName<T, TId> where T : Identifiable<TId>

Проблема в том, что вызывающий код должен быть двух типов. например. new ClassName<Person, int>()

Мне интересно, есть ли в .net 3.5 какой-нибудь способ написать это так, чтобы TId мог быть выведен T? Разрешение звонящему просто сделать new ClassName<Person>()?

Ответы [ 4 ]

2 голосов
/ 01 декабря 2011

Исходя из характера вашего вопроса, я предполагаю, что ваше ClassName не полагается на какие-либо методы в Identifiable, которые требуют TId (в противном случае вам потребуется тип.) В этом случае, одним из распространенных решений в этом случае являетсясоздать неуниверсальный базовый интерфейс со всеми методами, для которых не требуется тип TId.Тогда у вас есть:

interface Identifiable<TId> : Identifiable //Not a standard interface name, btw

, и ваше ограничение становится:

public class ClassName<T> where T : Identifiable

Предполагая, что вам действительно нужен тип TId, но вы просто хотите упростить синтаксис конструкции,Один из вариантов, если ваш конструктор использует экземпляр Identifiable (например, Person в вашем примере), это изменить конструктор на фабричный метод:

public static ClassName<T, TId> FromIdentifiable<T,TId>(T identifiable) where T: Identifiable<TId>

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

1 голос
/ 01 декабря 2011

Если в большинстве случаев ваш класс будет иметь форму ClassName<Person, int>, где тип T (Person) - это то, что меняется в большинстве случаев, а тип TId почти всегда int, вы можете предоставить частично разрешенный класс, который предоставляет тип TId, но сохраняет тип T свободным. Основным недостатком этого является то, что у вас будет несколько классов, которые должны иметь разные имена.

public class BaseClassName<T, TId> where T: Identifiable<TId> 
{ }

public class ClassName<T> : ClassName<T, int> 
{ }

var x = new ClassName<Person>();

Для менее частого случая, когда вы не хотите использовать int в качестве TId, класс arity 2 все еще доступен:

var y = new BaseClassName<Person, int>()
1 голос
/ 01 декабря 2011

AFAIK, это невозможно с предложением where.Вы можете использовать кодовые контракты (например, в .Net 4) и добавить

Contract.Requires(T is Identifiable<TId>);

к своему коду.Я не знаю, есть ли способ применить это в .Net 3.5.

1 голос
/ 01 декабря 2011

Нет. Вам необходимо указать параметр типа для Identifiable<>; Как вы могли бы сделать это без объявления параметра в объявлении класса:

public class ClassName<T> where T : Identifiable<?WhatDoWePutHere?> 
...