Suppose I have the following interface:
public interface IMessageProcessor<T> where T: BaseMessage {
void Process(T msg);
}
I have an abstract class that implements this interface:
public abstract class AMessageProcessor<T> : IMessageProcessor<T> where T : BaseMessage {
protected Controller Controller { get; private set; }
public AMessageProcessor(Controller controller) {
Controller = controller;
}
public abstract void Process(T msg);
}
then I have a message:
public class RRMessage : BaseMessage {
...
}
and then I have an implementation:
public class RRMessageProcessor : AMessageProcessor<RRMessage> {
public RRMessageProcessor(Controller controller) : base(controller) {}
public override void Process(RRMessage msg) {
//do something here
}
}
Now in another class I would like to make a list of these processors for different messages:
public readonly List<AMessageProcessor<BaseMessage>> AvailableMessageProcessors;
public MessageProcessingStrategy(Controller controller) {
AvailableMessageProcessors = new List<AMessageProcessor<BaseMessage>>();
/* ----- ERROR HAPPENS AT THIS LINE ------ */
AvailableMessageProcessors.Add(new RRMessageProcessor(controller));
}
And I get this error:
Error CS1503 Argument 1: cannot convert from 'RRMessageProcessor' to
'AMessageProcessor<BaseMessage>'
Seems like that conversion should work... Why can't it convert? How can I get it to work?
I had a problem in my other answer (deleted) about covariant types in parameters but an approach like this may solves your problem:
Defines a BaseMessageProcessor class (could be AMessageProcessor) like this one:
public abstract class BaseMessageProcessor
{
protected Controller Controller { get; private set; }
public BaseMessageProcessor(Controller controller)
{
Controller = controller;
}
public void Process<T>(T msg) where T : BaseMessage
{
if (this is IMessageProcessor<T>)
(this as IMessageProcessor<T>).Process(msg);
throw new NotSupportedException();
}
}
Defines an interface IMessageProcessorOf<T>:
public interface IMessageProcessor<T> where T : BaseMessage
{
void Process(T msg);
}
Defines concrete processors inheriting of BaseMessageProcessor and implementing (explicitly) IMessageProcessorOf<T>:
public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessorOf<RRMessage>
{
public RRMessageProcessor(Controller controller) : base(controller) { }
void IMessageProcessor<RRMessage>.Process(RRMessage msg)
{
...
}
}
This solution allows you to work with AvailableMessageProcessors:
public List<BaseMessageProcessor> AvailableMessageProcessors;
...
AvailableMessageProcessors = new List<BaseMessageProcessor>();
AvailableMessageProcessors.Add(new RRMessageProcessor(controller));
So, if you have 2 messages types like RRMessage and SSMessage, you can define one MultiMessageProcessor:
public class MultiMessageProcessor : BaseMessageProcessor, IMessageProcessorOf<RRMessage>, IMessageProcessorOf<SSMessage>
{
public MultiMessageProcessor(Controller controller) : base(controller) { }
void IMessageProcessorOf<RRMessage>.Process(RRMessage msg)
{
...
}
void IMessageProcessorOf<SSMessage>.Process(SSMessage msg)
{
...
}
}
The calls to Process() method will be made through BaseMessageProcessor.Process<>:
multiProcessor.Process(new RRMessage());
multiProcessor.Process(new SSMessage());
Or just use RRMessageProcessor and define a SSMessageProcessor using the same idea like before.
This isn't the cleanest/prettiest way to do it but it seems to work. Here's what I changed in AMessageProcessor:
public abstract class AMessageProcessor : IMessageProcessor<BaseMessage>
protected Controller Controller { get; private set; }
public AMessageProcessor(Controller controller) {
Controller = controller;
}
/* ----- REALLY DON'T WANT TO OVERRIDE THIS METHOD EVERYWHERE --- */
public abstract void Process(BaseMessage msg);
}
And then changing the RRMessageProcessor as:
public class RRMessageProcessor : AMessageProcessor, IMessageProcessor<RRMessage> {
public RRMessageProcessor(Controller controller) : base(controller) {}
/* ----- REALLY DON'T WANT TO OVERRIDE THIS METHOD LIKE THIS EVERYWHERE --- */
public override void Process(BaseMessage msg) {
Process(msg as RRMessage);
}
public void Process(RRMessage msg) {
//do something here
}
}
On your generic type you'll need to define the type as covariant. See https://msdn.microsoft.com/en-us/library/dd997386.aspx
This should work
public interface IMessageProcessor<in T> where T : BaseMessage
{
void Process(T msg);
}
You can easily solve your problem by redefining
public readonly List<AMessageProcessor<BaseMessage>> AvailableMessageProcessors;
into
public readonly List<RRMessageProcessor> AvailableMessageProcessors;
So you don't have cast problems and you're using the you're custom objects
hope to help!
Related
Good day everyone.
I wanna be able to do something like this
public class CommandExecutor
{
public List<ICommand> _commandList = new List<ICommand>()
public void ExecuteCommands()
{
for(int i = 0; i < _commandList.Count; i++)
{
_commandList[i].Execute();
}
}
}
With this setup:
public interface ICommand
{
void Execute();
}
public interface IDirectionalCommand : ICommand
{
}
public interface IImpulseCommand : ICommand
{
}
public class ExampleCommand1 : IImpulseCommand
{
public void Execute()
{
DoStuff();
}
}
public class ExampleCommand2 : IDirectionalCommand
{
public void Execute(Vector2 direction)
{
DoStuff(direction);
}
}
But I don't understand how this could be done.
PS: sorry if the title doesn't fully capture the question here, I'm having a hard time wording this problem.
That's wrong totally .. cause your interface have not defined any method named Execute which could accept a parameter ... what you are doing below code sample is nothing but hiding the interface method definition and defining a new definition of Execute() which accepts a parameter ...
public class ExampleCommand2 : IDirectionalCommand
{
public void Execute(Vector2 direction)
{
DoStuff(direction);
}
}
What you can do .. define a overload of same method (Method Overloading) in your interface like below which accepts a Vector2 type argument
public interface ICommand
{
void Execute();
void Execute(Vector2 direction);
}
I create child objects (Customer, Product, ...) and invoke method ApplyChange in parent class (AggregateRoot), from that method I would like to call method Apply in child class for passed event. Is it possible using reflection or I should change something?
public abstract class AggregateRoot
{
public void ApplyChange(IEvent #event)
{
Apply(#event); // how to call this method?
}
}
public class Customer : AggregateRoot
{
private void Apply(CustomerCreatedEvent e)
{
Console.WriteLine("CustomerCreatedEvent");
}
}
public class Product : AggregateRoot
{
private void Apply(ProductCreatedEvent e)
{
Console.WriteLine("ProductCreatedEvent");
}
}
public interface IEvent
{
}
public class CustomerCreatedEvent : IEvent
{
}
public class ProductCreatedEvent : IEvent
{
}
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer();
customer.ApplyChange(new CustomerCreatedEvent());
Product product = new Product();
product.ApplyChange(new ProductCreatedEvent());
}
}
Is it possible using reflection or I should change something?
I focused for now on the non-reflection, as IMO reflection should be the last resort here.
Option 1: abstract method
You could make Apply an abstract method en then you could call it from AggregateRoot.
e.g.
using System;
public abstract class AggregateRoot
{
public void ApplyChange(IEvent #event)
{
Apply(#event); // how to call this method?
}
protected abstract void Apply(IEvent e);
}
public class Customer : AggregateRoot
{
protected override void Apply(IEvent e)
{
if (e is CustomerCreatedEvent)
{
Console.WriteLine("CustomerCreatedEvent");
}
}
}
public class Product : AggregateRoot
{
protected override void Apply(IEvent e)
{
if (e is ProductCreatedEvent)
{
Console.WriteLine("ProductCreatedEvent");
}
}
}
public interface IEvent
{
}
public class CustomerCreatedEvent : IEvent
{
}
public class ProductCreatedEvent : IEvent
{
}
But please note, it has it downsides as:
methods needs to non-private
the should have the same parameter type for Apply. (IEvent parameter) - so I've added the type check inside the Apply methods.
Option 2: abstract method and generic AggregateRoot
Another option is to make AggregateRoot generic for the type IEvent, e.g. something like this.
using System;
public abstract class AggregateRoot<TEvent>
where TEvent : IEvent
{
public void ApplyChange(TEvent #event)
{
Apply(#event); // how to call this method?
}
protected abstract void Apply(TEvent e);
}
public class Customer : AggregateRoot<CustomerCreatedEvent>
{
protected override void Apply(CustomerCreatedEvent e)
{
Console.WriteLine("CustomerCreatedEvent");
}
}
public class Product : AggregateRoot<ProductCreatedEvent>
{
protected override void Apply(ProductCreatedEvent e)
{
Console.WriteLine("ProductCreatedEvent");
}
}
public interface IEvent
{
}
public class CustomerCreatedEvent : IEvent
{
}
public class ProductCreatedEvent : IEvent
{
}
Note I've changed also ApplyChange in this case.
If those things won't solve your problem, please elaborate what you are trying to archive, otherwise this will be a XY problem
I want to reuse Cook method functionality, but still pass different parameters to execute:
public void Cook(BasicRequest request,IBaseInterface base)
{
// Some code
// More code
request.Execute(base);
}
public class BasicRequest
{
public abstract void Execute(IBaseInterface baseInterface)
}
public class RequestA : BasicRequest
{
public void Execute(IBaseInterface base)
{
var derived = (DerivedClassA)base;
// Do stuff with derived
}
}
public class RequestB : BasicRequest
{
public void Execute(IBaseInterface base)
{
var derived = (DerivedClassB)base;
// Do stuff with derived
}
}
public interface IDerivedClassA : IBaseInterface {}
public interface IDerivedClassB : IBaseInterface {}
I have a design issue here that casting is needed on each of requests execute methods.
How can I make this code cleaner ?
You should be using generics.
Update the BaseRequest to a generic class:
public abstract class BasicRequest<T> where T:IBaseInterface
{
public abstract void Execute(T baseInterface);
}
Change your class Cook method as follows:
public void Cook<T>(BasicRequest<T> request, T ibase) where T:IBaseInterface
{
// Some code
// More code
request.Execute(ibase);
}
Change your classes,
public class RequestA : BasicRequest<DerivedClassA>
{
public override void Execute(DerivedClassA ibase)
{
// Do stuff with derived
}
}
public class RequestB : BasicRequest<DerivedClassB>
{
public override void Execute(DerivedClassB ibase)
{
// Do stuff with derived
}
}
I'm trying to implement a generic abstract method with a type constraint, then Implement it multiple times using different specified types.
public abstract class Ability
{
public abstract void BindToStation<T>(T station) where T : Station;
}
public class DashAbility : Ability
{
public override void BindToStation<NavStation>(NavStation station){ }
public override void BindToStation<CannonStation>(CannonStation station){ }
}
But I get an error which says the method has already been defined with the same paramater types.
I'm guessing that the compiler treats any generic paramater as the same in terms of the method signature, so these two methods look the same to it.
Still though, I'm wondering if theres a way to have generic method overloading using specific types.. ?
You can't do exactly what you want, but you can try an approach like this:
interface IBindableTo<T> where T : Station
{
void BindToStation(T station);
}
abstract class Ability
{
public abstract void BindToStation<T>(T station) where T : Station;
}
class DashAbility : Ability, IBindableTo<NavStation>, IBindableTo<CannonStation>
{
public override void BindToStation<T>(T station)
{
if (this is IBindableTo<T> binnder)
{
binnder.BindToStation(station);
return;
}
throw new NotSupportedException();
}
void IBindableTo<NavStation>.BindToStation(NavStation station)
{
...
}
void IBindableTo<CannonStation>.BindToStation(CannonStation station)
{
...
}
}
Hope this helps.
C# doesn't support specialization in that way, and neither does C++ easily when you want to specialize on runtime type.
But you can use polymorphism, so you can use double-dispatch:
public abstract class Station {
internal abstract void DashBindToStation();
}
public class NavStation : Station {
internal override void DashBindToStation() {
throw new NotImplementedException();
}
}
public class CannonStation : Station {
internal override void DashBindToStation() {
throw new NotImplementedException();
}
}
public abstract class Ability {
public abstract void BindToStation(Station station);
}
public class DashAbility : Ability {
public override void BindToStation(Station station) {
station.DashBindToStation();
}
}
Another possibility with C# is to use runtime dispatching using dynamic:
public abstract class Station {
}
public class NavStation : Station {
}
public class CannonStation : Station {
}
public abstract class Ability {
public abstract void BindToStation(Station station);
}
public class DashAbility : Ability {
public void BindToStation(NavStation station) {
}
public void BindToStation(CannonStation station) {
}
public override void BindToStation(Station station) {
BindToStation((dynamic)station);
}
}
Hi everyone I am programming in Unity3d with C# and while I was writing my code I stumbled with a little issue, I write to you an example because I dont know explain me.
class Base
{
public string name;
}
class Derived : Base
{
public void Gun();
}
class BasePlayer
{
public Base x;
}
class SoldierPlayer : BasePlayer
{
}
The situation is this, I want to do something like that
SoldierPlayer.x.Gun();
But I don't know how do it
The real case is this
public class BasePlayerController : MonoBehaviour
{
public BasePlayerManager playerManager;
...
public class RobotPlayerController : BasePlayerController {
...
playerManager = gameObject.AddComponent<RobotPlayerManager>();
And I will use new methods
UPDATE 1
I did a example better, I want to do in Base Controller manager.user.energy and be treated as the next type RobotManager.RobotUser.energy
BaseController
BaseManager
BaseUser
class BaseController
{
BaseManager manager;
public virtual void Move(int x,int y)...
}
class BaseManager {
BaseUser user;
public virtual Pause(bool state);
}
class BaseUser {
int life
}
RobotController
RobotManager
RobotUser
class RobotController : BaseController
{
// manager as RobotManager?
public void Ray(int x,int y);
}
class RobotManager : BaseManager
{
// user as RobotUser?
}
class RobotUser : BaseUser
{
int energy;
}
UPDATE 2
I seek to do this
public Run()
{
RobotController rc = new RobotController();
rc.manager.energy;
}
You can't call SoldierPlayer.x.Gun(); because SoldierPlayer.x has type Base which has not method Gun(). OOP world and C# can provide you many solutions, your choose depends on your goals.
some of them (order by best practise):
1) Overriding Polymorphism. Add .Gun() method to Base class and implemend it in derived classes. For example
class Base
{
public string name;
public void virtual Gun()
{
Trace.Log("I'm base class, i can't do anything");
}
}
class Derived : Base
{
public override void Gun()
{
Consule.WriteLine("Hello i have gun");
}
}
class Derived2 : Base
{
public override void Gun()
{
Consule.WriteLine("Hello i have 2 guns");
}
}
2) Overloading Polymorphism In many source this method is mentioned like some kind of polymorphism AD-HOC
public void GunAction(Derived2 o)
{
o.Gun();
}
public void GunAction(Derived1 o)
{
o.Gun();
}
public void GunAction(Base o)
{
Trace.Log("I'm base class, i can't do anything");
}
3) is-cast
public void GunAction(Base o)
{
if(o is Derived1 )
o.Gun();
if(o is Derived2 )
o.Gun();
}
UPDATE 1 answering to your new requirements
class BaseController
{
public BaseManager manager;
...
class RobotController1 : BaseController
{
// manager as RobotManager? - no it is stil BaseManager
public void Ray(int x,int y);
}
class RobotController2 : BaseController
{
// manager as RobotManager? - yes. now it is RobotManager
public void Ray(int x,int y);
public RobotController2()
{
manager = new RobotManager();
}
}
public void Run()
{
var controller = new RobotController2();// you have RobotManager
controller.manager = new BaseManager();// it is again BaseManager
}