1

I have a generic interface like so:

public interface IHandler { T Process<T>(IProcess process) where T : new(); } 

At times I would like to Implement interface concretely, for example:

public class BoolHandler : IHandler { public bool Process<bool>(IProcess process) { // Do some work - set to true or false return true; } } 

Is this possible?

EDIT: currently I could have done this:

// Injecct handler in Main and work with single handler ViewModel model = handler.Process<ViewModel>(process); DifferentModel model = handler.Process<DifferentModel >(process); 

With the suggestions listed I would have to do this (which I'm trying to avoid-it requires me to create bunch of handlers on the fly):

IHandler<ViewModel> handler = new Handler<ViewModel>(); ViewModel viewModel = handler.Process(process); IHandler<DifferentModel> handler = new Handler<DifferentModel>(); // Create yet another handler - arrr DifferentModel viewModel = handler.Process(process); 
13
  • 5
    Move the parameter T to the IHandler interface and remove it from the Process method. Generic parameters on methods need to work uniformly for all applicable types which your implementation cannot. Commented Oct 19, 2016 at 16:47
  • Will the implementation depend on the type that provided? If so, then the method is not "generic" Commented Oct 19, 2016 at 16:55
  • Would BoolHandler and the other handlers be used by the same consumer (that wants to consume them polymorphically)? If not, you can have two interfaces, a non-generic interface with a generic method, and a generic interface with a non-generic method. Commented Oct 19, 2016 at 17:19
  • Can you please provide a sample? Commented Oct 19, 2016 at 17:20
  • Is there some method that takes in a IHandler? e.g. void ConsumeHandler(IHandler handler, ...)? Would you want to pass BoolHandler (that wants to implement the method concretely) and other types that want to implement the generic method, interchangeably? If not, then these should have different interfaces. Commented Oct 19, 2016 at 17:24

4 Answers 4

3

No, it is not possible. Your interface states that any implementing class must have a method where that method can be used with any type [meeting the generic constraints]. If your class only works for, say, boolean values, then you are not fulfilling the contract that the interface specifies, and so the type cannot implement that interface.

Sign up to request clarification or add additional context in comments.

Comments

2

As far as I understand your question (from the comment exchange), some handlers can handle any type T (or many types T) and other handlers can handle only a single type. Also, you would like to consume these handlers within one consumer polymorphically.

Here is what you can do:

Create two interfaces like this:

public interface IHandler //Can handle many types { T Process<T>(int process); bool CanProcess<T>(); } public interface IHandler<T> //Can handle a single type { T Process(int process); } 

And then create an adapter from IHandler<T> to IHandler like this:

public class Adaptor<T> : IHandler { private readonly IHandler<T> handler; public Adaptor(IHandler<T> handler) { this.handler = handler; } public T1 Process<T1>(int process) { if(!CanProcess<T1>()) throw new Exception( "Contract violated. I cannot handle type " + typeof(T1).Name); return (T1)(object)handler.Process(process); } public bool CanProcess<T1>() { return typeof (T1) == typeof (T); } } 

Now, your composite can do something like this:

public class CompositeHandler : IHandler { private readonly IHandler[] handlers; public CompositeHandler(params IHandler[] handlers) { this.handlers = handlers; } public T Process<T>(int process) { var handler = handlers.FirstOrDefault(h => h.CanProcess<T>()); if(handler == null) throw new Exception( "Contract violated. I cannot handle type " + typeof(T).Name); return handler.Process<T>(process); } public bool CanProcess<T>() { return handlers.Any(h => h.CanProcess<T>()); } } 

Now, you can adapt any IHandler<T> implementation to IHandler and use it normally as IHandler. For instance, you can use it as part of the composite.

Here is an example composition:

var service = new CompositeHandler( new TypeThatImplementsTheNonGenericInterface(), new Type2ThatImplementsTheNonGenericInterface(), new Adaptor<SomeType>( new TypeThatImplementsTheGenericInterface<SomeType>())); 

1 Comment

this helped a lot!.= Thank you
0

you could try this pattern

 public interface IHandler<T> where T : new() { T Process(IProcess process); } public interface IProcess { } public class BoolHandler : IHandler<bool> { public bool Process(IProcess process) { throw new NotImplementedException(); } } 

6 Comments

just noticed that's what Lee said in his comment - anyway here it is written out for you
The problem with this approach is that I have to create separate handler for each Type. With what I have above I could do var result = _handler.Process<MyResult>();
@ShaneKm - How is the implementation of Process going to create an instance of any type you provide? (e.g. work for both bool and MyResult). This isn't possible in general (ignoring reflection) and if you're going to do that you can move the logic out of Process completely.
@Lee See the definition of Activator.CreateInstance<T> for one example. But in the case of the interface provided, that it specifies the generic argument's type has a parameterless constructor makes constructing an instance of it to return rather easy.
@Servy - Yes they could do something like that although new bool() is false but the example in the question returns true so I assume the logic is more complicated.
|
0

I know some will say that this is not a good practice, but it is an alternative. You can replace the generic T with object in the interface, and do some casts:

public interface IHandler { object Process(IProcess process); } public class BoolHandler : IHandler { object Process(IProcess process){ return true;} } 

It will be something like implementig the interface with the generic declared, but this way you promise the users that BoolHandler will always return a bool.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.