Lately I've stuck with some project. What I want to do?
I have some number of classes. Let's say something like that:
public class ActionEventArgs : EventArgs
{
public Creature actor;
}
public class LocationEventArgs : ActionEventArgs
{
public Location loc;
}
public class Action
{
public virtual void Do(object sender, ActionEventArgs e)
{
//... do something with it;
}
}
public class LocationAction : Action
{
public override void Do(object sender, LocationEventArgs e) // error, signatures differs
{
//... do something with it;
}
}
public class MainClass
{
public Action a { get; protected set; }
public void InitAction()
{
a = new LocationAction();
}
public void DoAction(Creature actor, Location location)
{
a.Do(this, new LocationEventArgs() { actor = actor, loc = location });
}
}
Well, it didn't work because of different methods signatures. Ok.
Of course, I can use something like class checks like:
public class LocationAction : Action
{
public override void Do(Action sender, ActionEventArgs e)
{
if (e is LocationEventArgs) throw new ArgumentException("e must be LocationEventArgs");
//... do something with it;
}
}
But I don't really like it, because it's only runtime thing. So, the question is: how to do this properly? Is there a way?
I think you want to use generics:
public class Action<TArg> where TArg : ActionEventArgs
{
public virtual void Do(object sender, TArg e)
{
// can access 'e.actor'
}
}
public class LocationAction : Action<LocationEventArgs>
{
public override void Do(object sender, LocationEventArgs e)
{
// can access 'e.actor' and 'e.loc'
}
}
I think what you are willing to do goes against the principle itself. You can't override and change the parameters. maybe add a
public override void Do(object sender, LocationEventArgs e) // error,
signatures differs
{
//... do something with it;
}
in your action class ?
Related
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 try to pass the bool bake value from one class(attribute class) to the solve instance(buttonTest class).
I already tried several things as the Get Method and write a property without sucess.
namespace buttonTest
{
public class buttonTestComponent : GH_Component
{
public override void CreateAttributes()
{
m_attributes = new Attributes_Custom(this);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
Circle circle = new Circle(2.00);
//here I want to bake
}
public class Attributes_Custom : GH_ComponentAttributes
{
public Attributes_Custom(GH_Component owner) : base(owner) { }
protected override void Layout()
bool bake;
public bool Bake
{
get { return bake; }
}
public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e)
{
if (e.Button == MouseButtons.Left)
{
RectangleF rec = ButtonBounds;
if (rec.Contains(e.CanvasLocation))
{
bool bake = true;
MessageBox.Show("Hello World", "Hello World", MessageBoxButtons.OK);
return GH_ObjectResponse.Handled;
}
}
return base.RespondToMouseDown(sender, e);
}
}
}
I am a beginner so I hope it is possible to understand.
Thanks to everybody
if I try to use m_attributes.Bake I get the following error message:
error message
If I understood the question correctly, you need something like the following.
The buttonTestComponent class:
public class buttonTestComponent : GH_Component
{
private Attributes_Custom m_attributes;
public override void CreateAttributes()
{
m_attributes = new Attributes_Custom(this);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
Circle circle = new Circle(2.00);
//use m_attributes.Bake here
}
}
And you leave Attributes_Custom class as it is.
My goal is to have the Abstract class update on its own once Consume is called on one of the derived classes.
Imagine this:
public interface IConsumable
{
void Consume();
}
public abstract class AbstractConsumable : IConsumable
{
private bool _consumed = false;
public virtual void Consume()
{
_consumed = true;
}
}
public class HealthyConsumable: AbstractConsumable
{
public override void Consume()
{
// Do something healthy and ...
base.Consume(); // Would like to avoid this...
}
}
public class PoisonousConsumable: AbstractConsumable
{
public override void Consume()
{
// Do something poisonous and ...
base.Consume(); // Would like to avoid this...
}
}
What I would like to achieve here is not having to call base.Consume() on the override methods, but still have the abstract class set _consumed once the derived classes call their Consume() methods.
You could make Consume none virtual and within it you called another protected virtual (or abstract method) that can contain code that be change by sub classes. Consumers of your class can only call the public Consume method but this will intern call the sub class implementation specific code
public interface IConsumable
{
void Consume();
}
public abstract class AbstractConsumable : IConsumable
{
private bool _consumed = false;
public void Consume()
{
_consumed = true;
InternalConsumerBehaviour();
}
protected virtual void InternalConsumeBehaviour()
{
//default do nothing could potentially mark this method abstract rather than virtual its up to you
}
}
public class HealthyConsumable: AbstractConsumable
{
protected override void InternalConsumeBehaviour()
{
// Do something healthy and ...
}
}
public class PoisonousConsumable: AbstractConsumable
{
protected override void InternalConsumeBehaviour()
{
// Do something poisonous and ...
}
}
If I get what you're asking right you could do something like this:
public interface IConsumable
{
void Consume();
}
public abstract class AbstractConsumable : IConsumable
{
private bool _consumed = false;
public abstract void ConsumeEffects();
public void Consume()
{
this.ConsumeEffects();
_consumed = true;
}
}
public class HealthyConsumable: AbstractConsumable
{
public override void ConsumeEffects()
{
// Do something healthy and ...
// Consume will get called in the base
}
}
public class PoisonousConsumable: AbstractConsumable
{
public override void ConsumeEffects()
{
// Do something poisonous and ...
// Consume will get called in the base
}
}
I have a parent class that is firing an event to derived classes. The problem is that the event handler is alway null.
Class Plugin()
{
public delegate void BufferReadyHandler(string str);
public event BufferReadyHandler OnBufferReady;
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
protected void Sp_DataReceived_Parent(object sender, SerialDataReceivedEventArgs e)
{
strCommonBuffer += serial.ReadExisting();
if (strCommonBuffer.Contains("\r\n"))
{
if (OnBufferReady != null) <<-------NULL
OnBufferReady(strCommonBuffer);
strCommonBuffer = string.Empty;
}
}
}
then there are some derived classes that are linked to that event:
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType) : base(_guyType)
{
...
OnBufferReady += ClassIO_OnBufferReady;
}
private void ClassIO_OnBufferReady(string str)
{
...
}
}
the problem is that the OnBufferReady event in the parent class is alway null and therefore never fired.
Thanks for any help.
I might be wrong but have you thought about making the event static?
public delegate void BufferReadyHandler(string str);
public static event BufferReadyHandler OnBufferReady;
I am not sure why you are having this problem, I suspect it has something to do with the code you have not shown us. However in this situation I would not have the child subscribe to the event at all, instead make a protected method that raises the event that the child can override.
Here is how I would implement the class.
public class BufferReadyEventArgs : EventArgs
{
public BufferReadyEventArgs(string commonBuffer)
{
CommonBuffer = commonBuffer;
}
public string CommonBuffer {get; private set;}
}
Class Plugin()
{
public event EventHandler<BufferReadyEventArgs> OnBufferReady;
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
protected void Sp_DataReceived_Parent(object sender, SerialDataReceivedEventArgs e)
{
strCommonBuffer += serial.ReadExisting();
if (strCommonBuffer.Contains("\r\n"))
{
RaiseOnBufferReady(strCommonBuffer);
strCommonBuffer = string.Empty;
}
}
protected virtual void RaiseOnBufferReady(string commonBuffer)
{
var temp = OnBufferReady;
if(temp != null)
temp(this, new BufferReadyEventArgs(commonBuffer));
}
}
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType) : base(_guyType)
{
...
}
protected override void RaiseOnBufferReady(string commonBuffer)
{
base.RaiseOnBufferReady(commonBuffer);
...
}
}
Here is a working example based on your code:
using System;
using System.Collections.Generic;
public class MyClass
{
public static void Main()
{
ClassIO c = new ClassIO();
c.DataReceived();
Console.ReadLine();
}
}
public class ClassPlugin
{
public delegate void BufferReadyHandler(string str);
public event BufferReadyHandler OnBufferReady;
public ClassPlugin()
{
}
public void DataReceived()
{
if (OnBufferReady != null) {
OnBufferReady("Calling OnBufferReady");
}
}
}
public class ClassIO : ClassPlugin
{
public ClassIO() : base()
{
OnBufferReady += ClassIO_OnBufferReady;
}
private void ClassIO_OnBufferReady(string str)
{
Console.WriteLine("Inside ClassIO_OnBufferReady");
}
}
I don't understand why you would like to work with events in the first place for communication between parent and derived class.
If you need this communication, you would be better of with an (abstract) method in your base class that you implement in your derived classes.
If you need communication to all instances of derived types, you should look into composition instead of inheritance. Make some sort of manager instance that holds references to a list of instances of that base type and invokes a certain method on each of them in case of an 'event'.
We have an exercise about inheritance in c#. Now my problem is that what will i put in the question mark and in the if statement to know that the program passed a Person class or an Animal class or any class under InventoryApplication namespace. :)
private void AddButton_Click(object sender, EventArgs e)
{
Logic_Layer.Logic logic = new Logic();
//logic.Add<Person>();
}
namespace Logic_Layer
{
public class Logic
{
public void Add<InventoryApplication>() where InventoryApplication : ?
{
//if { }
}
public void delete() { }
public void edit() { }
public void search() { }
public void searchAll() { }
}
}
You can't use such a statement in the constraint. However, later in the method you can do this:
if (typeof(myObject).Namespace == "InventoryApplication")
{
...
}
What would be better is if the classes you want to test for (Animal, Person etc.) would implement an interface (say, IMyInterface).
For example:
void Add<T>(<T> param) where T : IMyInterface {/*...*/}