2016-08-17 2 views
1

Это, как я хочу, чтобы использовать его:C# - Возвращаясь к реализации, когда общий тип метода является интерфейсом

var fooStuff = _foo.DoBarStuff().GetFooStuff(id); 

Я хотел бы вернуться к осуществлению, когда DoBarStuff() вызывается так, что я могу позвонить GetFooStuff (id), чтобы получить fooStuff.

public interface IFoo() : IBar 
{ 
    FooStuff GetFooStuff(int id); 
} 

public class Foo 
{ 
    public FooStuff GetFooStuff(int id) 
    { 
     // get fooStuff 
     return fooStuff; 
    }  
} 

public interface IBar 
{ 
     T DoBarStuff<T>(); 
} 

public class Bar 
{ 
    public T DoBarStuff<T>() 
    { 
     // do bar stuff 
     return T; 
    } 
} 

T - любой интерфейс и когда «return T;» Выполняется. Мне нужна его реализация. Как и сейчас, я получаю эту ошибку под T на 'return T;' линия.

T - тип, который недопустим в данном контексте. Параметр типа имя недействительно на данный момент.

Спасибо!

+0

Подсказка: вы должны вернуть экземпляр Т, а не тип самого Т ... – ViRuSTriNiTy

+2

'T' - это тип. 'return T;' похоже на запись 'return int;'. Вернуть * что * int? Если ваш метод создал объект с типом T, верните его. Если вы не собираетесь ничего возвращать, не используйте возвращаемое значение в определении, используйте 'void'. –

+0

Посмотрите на это: http://stackoverflow.com/questions/731452/create-instance-of-generic-type#answer-731637 – Corporalis

ответ

2

Это должно работать:

public interface IBar 
{ 
    T DoBarStuff<T>() where T : class, new(); 
} 

public class Bar : IBar 
{ 
    public T DoBarStuff<T>() where T : class, new() 
    { 
     // do bar stuff 
     return new T(); 
    } 
} 

Но вы должны указать тип при использовании метода DoBarStuff:

Использование:var fooStuff = _foo.DoBarStuff<FooWhatEver>().GetFooStuff(id)


Если вы не захотите, сделайте свой общий класс/интерфейс:

public interface IBar<T> where T : class, new() 
{ 
    T DoBarStuff<T>(); 
} 

public class Bar<T> : IBar<T> where T : class, new() 
{ 
    public T DoBarStuff() 
    { 
     // do bar stuff 
     return new T(); 
    } 
} 

Использование:

IBar bar = new Bar<FooWhatEver>(); 
var fooStuff = _foo.DoBarStuff().GetFooStuff(id); 

Но все это не работает для интерфейса, только инстанциируемые классов (с конструктором по умолчанию).

Для интерфейсов вам нужно что-то сделать для преобразования между ними и их реализациями.

Простым способом является использование словаря (для целей тестирования, но вы можете использовать инфраструктуру инъекций зависимостей, как предлагалось @N_tro_P, даже если вы выбрали между одним из них, теперь не должна быть вашей главной целью).

Вы будете в конечном итоге с чем-то вроде этого (не забудьте наследуйте и общей части):

public class Bar // <T> or not depending on your choice 
// You can add this constraint to avoid value types (as int): 
// where T : class 
{ 
    Dictionary<Type, Type> _container = new Dictionary<Type, Type>(); 
    { 
     {typeof(IFoo), typeof(Foo)} 
    }; 

    public T DoBarStuff() // <T> or not depending on your choice 
    // You can add this constraint to avoid value types (as int): 
    // where T : class 
    { 
     // get fooStuff 

     return Activator.CreateInstance(_container[typeof(T)]); 
     // You will get an error if T is not in the container 
     // or if _container[typeof(T)] is not instantiable 
     // or doesn't have a default constructor. 
    } 
} 

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

+0

Что делать, если я хочу, чтобы T был каким-то интерфейсом, а не только IFoo? – User123

+0

Мой плохой, просто удалите IFoo в ограничении –

+0

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

0

Вы можете сделать это, но не как написать свою сигнатуру вызова.

У вас никогда не было вашей бары не использовать IBar и Foo использовать ее как интерфейс. Итак, вы должно изменить это. Возможно, вы сбиваете с толку, как взаимодействовать с интерфейсами.

Скорректированный код

public interface IFoo 
{ 
    FooStuff GetFooStuff(int id); 
} 

public class Foo : IFoo 
{ 
    public FooStuff GetFooStuff(int id) 
    { 
     // get fooStuff 
     return fooStuff; 
    }  
} 

public interface IBar 
{ 
     T DoBarStuff<T>(); 
} 

public class Bar : IBar 
{ 
    public T DoBarStuff<T>() 
    { 
     // do bar stuff 
     return container[typeof(T)]; 
    } 
} 

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

var fooStuff = _foo.DoBarStuff<BarStuff>().GetFooStuff(id); 

Вот как работают контейнеры зависимостей. Они хранят в нем словарь-экземпляр объекта с использованием типа в качестве ключа. т.е. Словарь экземпляров;

Тогда вы также можете иметь заводы, хранящиеся в другом месте, но для этого требуется соответствие вашим требованиям или вы просто предполагаете, что у них есть независимый доступ к их зависимостям, поэтому у вас будет Словарь> заводы;

В общем, я бы посмотрел на контейнеры зависимостей. Независимо от того, над чем вы работаете, вы можете просто называть его шаблоном, и многие из них уже сделали так, что вам не нужно катиться самостоятельно. Если вы хотите возвращать объекты по типу, это контейнер зависимостей. Кроме того, я бы рекомендовал вводить это, чтобы вы не были связаны с контейнером. Другими словами, завернуть его в интерфейсе, а затем использовать с полки один (Unity, MEF и т.д.)

public interface IDependencyContainer 
{ 
    T Resolve<T>(); 
    void Register<T>(T instance); 
    void Register<T>(Func<T> instance); 
} 
+0

Возможно, вам следует удалить код OP из вашего ответа, он избыточен (и даже не будет компилироваться). Вторая часть ответа полезна. – Groo

+0

Его код был неправильным, и я исправил его. –

+0

Я все еще вижу 'return T;', где OP получает ошибку компиляции. Это часть, которая исправлена ​​в [другом ответе] (http://stackoverflow.com/a/38998949/69809). – Groo

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