2015-05-26 2 views
-1

У меня есть приложение, написанное на C#. У моего приложения есть класс, который выглядит следующим образом:Использование генериков в интерфейсах в C#

public class FinderA 
{ 
    public IEnumerable<FinderA> GetItems() 
    { 
    return FinderA.FindAll(); 
    } 
} 

Я хочу, чтобы другие классы делали что-то подобное. Я не могу использовать базовый класс, потому что моя фактическая реализация уже использует базовый класс. По этой причине я хочу создать интерфейс. В настоящее время я пытаюсь следующее:

public interface IFinder 
{ 
    IEnumerable<T> GetItems(); 
} 

Когда я использую этот подход, я получаю ошибку во время компиляции, который говорит: «Тип или пространство имен имя„T“не может быть найдено (вы пропали без вести. .. «чтобы преодолеть это, я добавляю <T> к концу имени интерфейса, так это выглядит следующим образом:

public interface IFinder<T> 
{ 
    IEnumerable<T> GetItems(); 
} 

Это в свою очередь порождает другую ошибку во время компиляции, который говорит:» ​​Использование универсального типа «IFinder «требует 1 аргумент типа». Моя задача: я хочу, чтобы интерфейс был общим. Я не хочу передавать тип. Есть ли способ обойти это? Если да, то что/как?

+1

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

+1

@TimothyShields Он хочет, чтобы это было выведено; в частности, он хочет, чтобы общий аргумент всегда был типом реализации интерфейса. По крайней мере, так оно и есть. Конечно, такой функции нет в C#. – Servy

+0

Догадка, основанная на том, как вы определили FinderA: 'public interface IFinder {IEnumerable GetItems(); } ' – ASh

ответ

0

Нет никакого способа обойти это; вам нужно будет фактически предоставить аргумент generic type при объявлении того, что класс реализует интерфейс.

+0

Собственно, комментарий, сделанный ASh выше, затронул мою проблему. –

+0

@JQueryMobile Ну, это не вопрос, который вы на самом деле просили. Вы спросили, нужно ли вам предоставлять общие аргументы универсальному интерфейсу. Если бы вы описали фактическую проблему, которую у вас есть, мы могли бы помочь вам найти решения этой проблемы, но на самом деле вы этого не делали. – Servy

+0

Один человек, казалось, понял это. –

0

Если вы хотите, чтобы ваш интерфейс был общим, но вы не хотите указывать аргумент типа, вы можете вернуть IEnumerable<object>.

public interface IFinder { 
    IEnumerable<object> GetItems(); 
} 

Все типы класса простираются от System.Object, так что должно хватить для любого типа в вашем applicacion (перечислений и Структуры бы получить коробочный)

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

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

+0

Типы значений, такие как 'enum' и' struct's, будут просто вставляться в коробку. – juharr

+0

Это побеждает всю цель дженериков. Кроме того, значения типов * могут * быть возвращены, они просто получат коробку. – haim770

+0

Вы, парни, правы. Обновление моего ответа. –

0

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

public interface IFinder 
{ 
    IEnumerable<T> GetItems<T>(); 
} 

Ваш код может затем вызвать его, как, например:

IFinder finder = // Create finder instance 
IEnumerable<MyClass> discoveredClasses = finder.GetItems<MyClass>(); 

Если вы хотите, чтобы убедиться, что MyClass это класс, который реализует IFinder, вы можете ограничить метод.

public interface IFinder 
{ 
    IEnumerable<T> GetItems<T>() where T : IFinder; 
} 

Это вызовет следующее генерировать ошибку компилятора:

public class Foo 
{ 
} 

public class Bar 
{ 
    Bar() 
    { 
     IFinder finder = // Create finder. 
     // This fails because <T> (Foo) does not implement IFinder. 
     IEnumerable<Foo> fooItems = finder.GetItems<Foo>(); 
    } 
} 

, но это позволит следующее скомпилировать

public class MyFinderA : IFinder 
{ 
    IEnumerable<T> GetItems<T>() where T : IFinder 
    { 
     return // Create collection of T 
} 

public class Bar 
{ 
    Bar() 
    { 
     IFinder finder = // Create finder. 
     // This works as <T> (MyFinderA) is an IFinder implementation 
     IEnumerable<MyFinderA> finderItems = finder.GetItems<MyFinderA>(); 
    } 
} 
+0

Но методы, которые у него есть, должны выполнять этот контракт * не * изменяются в возвращаемом типе, поэтому метод не является концептуально общим, сам интерфейс. – Servy

+0

Тогда он должен показать нам лучший пример. Похоже, что это можно решить, добавив уровень интерфейсов на интерфейсы, если он хочет конкретно определить объекты, а затем получить их в общих чертах; Я не понимаю _how_ GetItems используется на практике с учетом его кода примера. –

Смежные вопросы