I have a class with functions:
class MyClass
{
public List<Attachment> Attachments;
public void A()
{
// Do something
}
public void B()
{
// Do something
}
}
class AttachmentA : Attachment
{
public void A()
{
// Do something else
RealA();
}
}
class AttachmentB : Attachment
{
public void B()
{
// Do something else
// RealB();
// No need to call base function here
}
}
I need in my code when I attach AttachmentA to MyClass that all the functions in MyClass that are also present in AttachmentA to be overridden by the functions in AttachmentA and also give access to the original functions in MyClass.
For example, I create MyClass and then attach AttachmentA instance to it. calling MyClass.A() will actually call AttachmentA.A() and the AttachmentA.RealA() will call the base function that was overridden.
I know this can be somehow done with something like using event handlers lists to handle overrides but is there an easy way to implement this?
Edit: I have no problem with long code that uses reflection as long as its present once and doesn't have to be even mentioned in any of the functions - maybe only when attaching attachement.
Edit: you wanted an example:
class MyClass
{
public List<Attachment> Attachments;
public MyClass()
{
Attachments = new List<Attachment>();
}
public void Attach(Attachment attachment)
{
Attachments.Add(attachment);
// Do some magic here
}
public void A()
{
Console.WriteLine("MyClass.A");
}
public void B()
{
Console.WriteLine("MyClass.B");
}
}
class AttachmentA : Attachment
{
public void A()
{
Console.WriteLine("AttachmentA.A");
RealA();
}
}
class AttachmentB : Attachment
{
public void B()
{
Console.WriteLine("AttachmentB.B");
}
}
public class Program
{
public static void Main(string[] Args)
{
MyClass aaa = new MyClass();
aaa.A(); // should print MyClass.A
aaa.B(); // should print MyClass.B
aaa.Attach(new AttachmentA());
aaa.Attach(new AttachmentB());
aaa.A(); // should print AttachmentA.A <newline> MyClass.A
aaa.B(); // should print AttachmentB.B
}
}
Edit: What I want to achieve here is like unit with attributes( = attachments). When the unit get an attachment of RandomSpeed, RandomSpeed will override the unit's GetSpeed and return random value. when it will get an attachment of evasion, it will override that units ReduceHP function and sometimes based on random value will not call the base function.
Edit: What will really solve this mess is to somehow use reflection to change virtual method tables, I'm gonna make a followup on a separate question. I keep this question here incase someone find a better way to do this.
As mentioned in comments, Decorator Pattern is what you are looking for.
http://en.wikipedia.org/wiki/Decorator_pattern
The decorator pattern can be used to
make it possible to extend (decorate)
the functionality of a certain object
at runtime, independently of other
instances of the same class, provided
some groundwork is done at design
time. This is achieved by designing a
new decorator class that wraps the
original class.
Why not take another approach? Have attachments implement interfaces based on what they want to override, for example ISpeedAttachment. Then you could, in the base speed function loop through attachments which implement ISpeedAttachment, calling them.
Have the interfaces return null if they haven't taken effect and you could then check they've all returned null and call the base class as appropriate, or pass in a ref parameter which you could adjust as necessary.
You should look into the behavioral patterns. For your particular problem I would recommend either the chain of responsibility or the strategy pattern.
If you don't want to introduce dependencies, like inheritance or interfaces to implement on MyClass then:
You can achieve this through delegates.
Long story short, you cannot override function in runtime without resorting to some obscure reflection magic, but you can declare delegates instead of functions. When you construct your class in the constructor fill the delegates with private methods which will be used for as long as no AttachmentA class comes in. And use those delegates instead of the methods.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
static class Program
{
static void Main(string[] args)
{
MyClass aaa = new MyClass();
aaa.A(); // should print MyClass.A
aaa.B(); // should print MyClass.B
aaa.Attach(new AttachmentA());
aaa.Attach(new AttachmentB());
aaa.A(); // should print AttachmentA.A <newline> MyClass.A
aaa.B(); // should print AttachmentB.B
}
}
class MyClass
{
public List<Attachment> Attachments;
public MyClass()
{
A = _A;
B = _B;
Attachments = new List<Attachment>();
}
public void Attach(Attachment attachment)
{
Attachments.Add(attachment);
// this is your magic
if (attachment.GetType() == typeof(AttachmentA)) {
A = ((AttachmentA)attachment).A;
}
else if (attachment.GetType() == typeof(AttachmentB))
{
B = ((AttachmentB)attachment).B;
}
}
public delegate void delegateA();
public delegate void delegateB();
public delegateA A;
public delegateB B;
public void _A()
{
Console.WriteLine("MyClass.A");
}
public void _B()
{
Console.WriteLine("MyClass.B");
}
}
class Attachment {
}
class AttachmentA : Attachment
{
public void A()
{
Console.WriteLine("AttachmentA.A");
}
}
class AttachmentB : Attachment
{
public void B()
{
Console.WriteLine("AttachmentB.B");
}
}
}
If you need the execution to start always in MyClass instead of the Attachment class you can wrap the delegates like here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
static class Program
{
static void Main(string[] args)
{
MyClass aaa = new MyClass();
aaa.A(); // should print MyClass.A
aaa.B(); // should print MyClass.B
aaa.Attach(new AttachmentA());
aaa.Attach(new AttachmentB());
aaa.A(); // should print AttachmentA.A <newline> MyClass.A
aaa.B(); // should print AttachmentB.B
}
}
class MyClass
{
public List<Attachment> Attachments;
public MyClass()
{
Attachments = new List<Attachment>();
}
public void Attach(Attachment attachment)
{
Attachments.Add(attachment);
if (attachment.GetType() == typeof(AttachmentA)) {
_A = ((AttachmentA)attachment).A;
}
else if (attachment.GetType() == typeof(AttachmentB))
{
_B = ((AttachmentB)attachment).B;
}
}
public delegate void delegateA();
public delegate void delegateB();
public delegateA _A;
public delegateB _B;
public void A()
{
if (_A != null)
{
_A();
}
else
{
Console.WriteLine("MyClass.A");
}
}
public void B()
{
if (_B != null)
{
_B();
}
else
{
Console.WriteLine("MyClass.B");
}
}
}
class Attachment {
}
class AttachmentA : Attachment
{
public void A()
{
Console.WriteLine("AttachmentA.A");
}
}
class AttachmentB : Attachment
{
public void B()
{
Console.WriteLine("AttachmentB.B");
}
}
}
You can shorten this to one delegate type if A and B have the same parameters and return type in your real scenario.
I'm not sure if dynamically overriding a class's functionality is possible, but you can achieve something similar by using different interfaces. Depending on the context you want to use this in, it may require only small redesign.
The standard way of doing it would be this:
using System;
class MyClass
{
public virtual void A()
{
Console.WriteLine("MyClass.A");
}
public virtual void B()
{
Console.WriteLine("MyClass.B");
}
}
class ClassA : MyClass
{
public override void A()
{
Console.WriteLine("AttachmentA.A");
base.A();
}
}
class ClassB : MyClass
{
public override void B()
{
Console.WriteLine("AttachmentB.B");
}
}
public class Program
{
public static void Main(string[] Args)
{
MyClass aaa = new ClassA();
MyClass bbb = new ClassB();
aaa.A(); // prints MyClass.A
aaa.B(); // prints MyClass.B
(aaa as ClassA).A(); // prints AttachmentA.A
(aaa as ClassA).B(); // prints MyClass.B
bbb.A(); // prints MyClass.A
bbb.B(); // prints MyClass.B
(bbb as ClassB).A(); // prints AttachmentB.A + MyClass.A
(bbb as ClassB).B(); // prints AttachmentB.B
}
}
Here's another example, similar to what blowdart suggested:
interface ICallMe
{
bool A();
bool B();
}
class MyClass
{
public ICallMe Attachment { get; set; }
public void A()
{
bool BaseFunction = true;
if (Attachment != null)
BaseFunction = Attachment.A();
if (BaseFunction)
Console.WriteLine("MyClass.A");
}
public void B()
{
bool BaseFunction = true;
if (Attachment != null)
BaseFunction = Attachment.B();
if (BaseFunction)
Console.WriteLine("MyClass.B");
}
}
class ClassA : ICallMe
{
public bool A()
{
Console.WriteLine("AttachmentA.A");
return true;
}
public bool B()
{
Console.WriteLine("AttachmentA.B");
return false;
}
}
static class Program
{
static void Main(string[] args)
{
MyClass aaa = new MyClass();
aaa.A(); // prints MyClass.A
aaa.B(); // prints MyClass.B
aaa.Attachment = new ClassA();
aaa.A(); // should print AttachmentA.A <newline> MyClass.A
aaa.B(); // should print AttachmentB.B
}
}
This only allows for a single attachment to be added. If you wanted to override the behavior of several functions separately, you could use a Collection of some sort to hold the attachments. Within the base class you'd need to loop through them and find the one you want to execute.
Related
consider the following game code:
public class Player : MonoBehaviour {
public void UseItem(Item item) {
item.Use(this);
}
public void GetDrunk() {}
}
public class Item {
public WhatInterface[] itemUsages;
public void Use(Player player) {
foreach(var usage in itemUsages) {
usage.Execute(new ItemUsageArgs {itemUser = player, itemUsed = this})
}
}
}
public class GameManager : MonoBehaviour {
public Player mainCharacter;
public Item beer = new Item {itemUsages = new [] {
new TestConsole(),
new DamageFromItem (),
new DrunkFromITem ()
}}
private void Start() {
mainCharacter.Use(beer);
}
}
public class TestConsole : WhatInterface {
public void Execute(BaseArgs args) {
Debug.Log("function call executed");
}
}
public class DamageFromItem : WhatInterface {
public void Execute(ItemUsageArgs args) {
Debug.Log(args.itemUser + " take damage from " + args.itemUsed);
}
}
public class DrunkFromITem : WhatInterface {
public void Execute(ItemUsageArgs args) {
args.itemUser.GetDrunk();
}
}
public class BaseArgs {}
public class ItemUsageArgs : BaseArgs {
public Player itemUser;
public Item itemUsed;
}
so how to create interface type code that is suited for itemUsages?
Or do I wrongly create the design for this context?
Basically I'm trying strategy pattern so that item usages could be vary for every kind of item.
Things I tried, creating IItemUsage interface:
public interface IItemUsage {
void Execute(ItemUsageArgs args);
// but then anything that needs to implement this interface must use this method, even though it only needs BaseArgs.
// TestConsole class must conform to Execute(ItemUsageArgs) signature..
}
public class TestConsole : IItemUsage {
public void Execute(BaseArgs args) {
Debug.Log("function call executed");
}
// this won't compile
}
Assuming this is all of your code, you can make IItemUsage generic, and contravairant on the generic parameter.
public interface IItemUsage<in T> where T: BaseArgs {
void Execute(T args);
}
Have TestConsole implement IItemUsage<BaseArgs> and the other two classes implement IItemUsage<ItemUsageArgs>.
Now you can put instances of all three classes into an IItemUsage<ItemUsageArgs>[]:
IItemUsage<ItemUsageArgs>[] arr = new IItemUsage<ItemUsageArgs>[] {
new TestConsole(), new DamageFromItem(), new DrunkFromITem()
};
If you want to implement interface with some method, which has input arguments, that can be different types, you must define base argument class or use interface parameter instead.
For example:
public interface IItemUsage
{
void Execute(IItemUsageArgs args);
}
public interface IItemUsageArgs
{
//place public part of all ItemUsageArgs
}
public class ItemUsageArgs1 : IItemUsageArgs
{
}
public class ItemUsageArgs2 : IItemUsageArgs
{
}
public class ItemUsage1 :IItemUsage
{
public void Execute(ItemUsageArgs1 args)
{
//do you need
}
void IItemUsage.Execute(IItemUsageArgs args)
{
Execute(args as ItemUsageArgs1);
}
}
public class ItemUsage2 : IItemUsage
{
public void Execute(ItemUsageArgs2 args)
{
//do you need
}
void IItemUsage.Execute(IItemUsageArgs args)
{
Execute(args as ItemUsageArgs2);
}
}
suppose I have this class:
Class Foo:
method1(){}
method2(){}
method3(){}
...
And suppose I have some action I wanted to do repeatedly in several methods in the class. Each action will take before the methods occur and after it occur. Is there an elegant way to implement it? The only way came to my mind:
private void Setup(Action action)
{
//Do something before
action
//Do something after
}
private void method1(args)
{
Setup(()=>method)
}
But it will make me call repeatedly call for Setup in each function I would like to implement it.
I have made a quick exemple with DispatchProxy
Inspiration : DispatchProxy
https://dotnetfiddle.net/GzDR9r
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
//https://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/
public class Program
{
public static void Main()
{
var foo = new Foo();
var decoratedFoo = AspectDecorator<IFoo>.Create(foo);
Console.WriteLine("\n\nClass:\n");
foo.method1();
foo.method2();
foo.method3();
Console.WriteLine("\n\nDecorated Class:\n");
decoratedFoo.method1();
decoratedFoo.method2();
decoratedFoo.method3();
}
}
public class Foo : IFoo{
public void method1(){Console.WriteLine("> call method1");}
public void method2(){Console.WriteLine("> call method2");}
public void method3(){Console.WriteLine("> call method3");}
}
public interface IFoo{
void method1();
void method2();
void method3();
}
public class AspectDecorator<T> : DispatchProxy
{
private T _impl;
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Console.WriteLine($"Before : {targetMethod.Name}");
var obj = _impl.GetType().GetMethod(targetMethod.Name).Invoke(_impl, args);
Console.WriteLine($"After : {targetMethod.Name}");
return obj;
}
public void SetTarget(T target)
{
this._impl = target;
}
public static T Create(T decorated)
{
object proxy = Create<T, AspectDecorator<T>>();
((AspectDecorator<T>) proxy)._impl=decorated;
return (T)proxy;
}
}
I would not be surprised if this has been answered somewhere, the problem is I am not sure how to phrase a search to find what I need. The things I have already found have either been too simplistic to be usable or poorly explained such that I cannot translate it into my own project. I had no formal instruction with event handlers, delegates, and the like (heck, I didn't even learn about Entity-Component Systems--or other design patterns--until long after I graduated college and was already employed as a programmer, and even then it wasn't something I learned at, or for, my job).
Essentially what I want to know is, what does the definition of Array.Sort<T>(T[] array, Comparison<T> comparison) look like?
There's clearly some kind of generalization going on, as myCompareDelegate(...) takes two arguments of any type. In almost everything I've found relating to Func arguments, a Func<> parameter requires explicitly declared types, with the exception of some sample code using an operator I am unfamiliar with:
SomeUtility(arg => new MyType());
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo");
}
It compiles but I have no idea what it does and as such, I do not know how to utilize it to create code that will run or do what I want to do.
My goal here is to be able to create an event system (yes, I'm aware that C# has an event system built in, but again, all the sample code I've seen is either simplified to the point of uselessness--listeners contained in the same class as the dispatcher--or complicated and unexplained). I want the following to be true:
a single function to register an event listener (for any Type of event and its subtypes)
a single function to dispatch an event (calling only the relevant listeners)
to be able to create new event types without having to modify the functions for registration and handling (no explicit types in the dispatcher beyond the base event class) provided the new event type extends the allowable event type (i.e. an Entity will only dispatch EntityEvents not WorldEvents).
I have a system that works currently, but it requires that all my handlers pass through a single "onEvent" function which takes a base event object and figures out what it's actual type is, passing that off to the true handler.
Eg:
//Entity implements IEventDispatcher
public SomeConstructor(Entity ent) {
//public delegate void EventListener(EventBase eventData); is declared
//in the IEventDispatcher interface.
ent.attachEvent(typeof(EntityEventPreRender), new EventListener(onEvent));
ent.attachEvent(typeof(EntityEventPostRender), new EventListener(onEvent));
}
//EntityEventPreRender extends EntityEventRender extends EntityEvent extends EventBase
//EntityEventPostRender extends EntityEventRender extends EntityEvent extends EventBase
public void onEvent(EventBase data) {
if(data is EntityEventPreRender)
onPre((EntityEventPreRender)data);
if(data is EntityEventPostRender)
onPost((EntityEventPostRender)data);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
attachEvent() here is a function that takes a Type (used as a HashMap key) and a Delegate and stores it in a list (the HashMap value). Dispatching the event just needs to pass the EventData object, which is queried for its type (via evt.GetType()) to retrieve the list of listeners, then invoking them: listItem(evt)
But I'd rather be able to just do this:
public SomeConstructor(Entity ent) {
ent.attachEvent(onPre);
ent.attachEvent(onPost);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
But I cannot, for the life of me, figure out how to do this because I do not know how to declare the attachEvent() function to take a generic function parameter the way Array.Sort<T>(T[] array, Comparison<T> comparison) does. I get the error:
"The type arguments for method doSomething<T>(SomeClass.Thing<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly."
I think you might be looking for something like the following:
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
In the above code, using PubSub and specifying a type for TMessage creates a new static class in memory with its own memory space allocated for storing a separate list of listeners. The compiler will ensure that only the substituted type for TMessage and its subclasses will be allowed in that list, provided you consistently use the base type as the type argument for the TMessage type parameter.
You would then use it like so:
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
...
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeListener
{
static SomeListener()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
// do something with the message
}
}
If you then create another class SomeOtherMessageType which does not inherit from SomeMessageType and make similar calls to it, it will only broadcast to listeners of that specific type.
EDITED:
Here is a full proof of concept that compiles that you can run in a console app to allay any remaining concerns you may have over efficacy of this technique.
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
SomeListener.Listen();
SomeOtherListener1.Listen();
SomeOtherListener2.Listen();
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher();
var publisher2 = new SomeOtherPublisher();
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
PubSub<SomeOtherMessageType>.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public static void Listen()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
EDITED AGAIN (Alternate proof of concept using an instance based pubs):
Here is a proof of concept using an instance based PubSub.
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
private static PubSub<SomeMessageType> pubSub1 = new PubSub<SomeMessageType>();
private static PubSub<SomeOtherMessageType> pubSub2 = new PubSub<SomeOtherMessageType>();
private static SomeListener listener1 = new SomeListener();
private static SomeOtherListener1 listener2 = new SomeOtherListener1();
private static SomeOtherListener2 listener3 = new SomeOtherListener2();
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
Program.listener1.Listen(Program.pubSub1);
Program.listener2.Listen(Program.pubSub2);
Program.listener3.Listen(Program.pubSub2);
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher(Program.pubSub1);
var publisher2 = new SomeOtherPublisher(Program.pubSub2);
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public class PubSub<TMessage>
{
private List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public void Listen(Action<TMessage> listener)
{
if (listener != null) this.listeners.Add(listener);
}
public void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) this.listeners.Remove(listener);
}
public void Broadcast(TMessage message)
{
foreach(var listener in this.listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
private PubSub<SomeMessageType> pubSub;
public SomePublisher(PubSub<SomeMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingCool(string description)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
private PubSub<SomeOtherMessageType> pubSub;
public SomeOtherPublisher(PubSub<SomeOtherMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public void Listen(PubSub<SomeMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
How can I add a method from class A to a delegate of class B without knowing in advance which method I will be adding and what class A is? And then call that delegate from class A?
class Class {
public string someProperty;
public delegate void myDelegate(Class obj);
myDelegate handler = new myDelegate(mainClassMethod); //here is the problem..
public void someMethod() {
handler();
}
}
class MainClass {
public static void Main() {
Class classObj = new Class();
classObj.someProperty = "hello";
public void mainClassMethod(Class obj) {
System.Console.WriteLine(obj.someProperty);
}
classObj.someMethod();
}
}
Should I use something other than delegates for this? By the way I am doing this in C#!
make mainClassMethod static and access it via class name MainClass. Also you cant declare nested functions as class members, you need to declare mainClassMethod separately.
class MainClass {
public static void Main()
{
Class classObj = new Class();
classObj.someProperty = "hello";
classObj.someMethod();
}
public static void mainClassMethod(Class obj)
{
System.Console.WriteLine(obj.someProperty);
}
}
Also you declared delegate void myDelegate(Class obj); so you need to pass instance of a Class as a parameter. In my example I pass object found by this reference, which is an object that you call someMethod at.
Now you can write:
class Class {
public string someProperty;
public delegate void myDelegate(Class obj);
myDelegate handler = new myDelegate(MainClass.mainClassMethod); //no error
public void someMethod()
{
handler(this);
}
}
I am experimenting with calling delegate functions from a delegate array. I've been able to create the array of delegates, but how do I call the delegate?
public delegate void pd();
public static class MyClass
{
static void p1()
{
//...
}
static void p2 ()
{
//...
}
//...
static pd[] delegates = new pd[] {
new pd( MyClass.p1 ),
new pd( MyClass.p2)
/* ... */
};
}
public class MainClass
{
static void Main()
{
// Call pd[0]
// Call pd[1]
}
}
EDIT: The reason for the array is that I need to call the delegate functions by an index as needed. They are not run in response to an event. I see a critical (stupid) error in my code as I had tried to execute the delegate function using the pd[] type rather than the name of the array (delegates).
If they're all the same type, why not just combine them into a single multicast delegate?
static pd delegateInstance = new pd(MyClass.p1) + new pd(MyClass.p2) ...;
...
pd();
public class MainClass
{
static void Main()
{
pd[0]();
pd[1]();
}
}
In .Net, any delegate is in fact actually a "multicast" delegate (it inherits from this built-in base class), and therefore contains an internal linked list which can contain any number of target delegates.
You can access this list by calling the method GetInvocationList() on the delegate itself. This method returns an array of Delegates...
The only restriction is that all the delegates inside of a given delegate's linked list must have the same signature, (be of the same delegate type). If you need your collection to be able to contain delegates of disparate types, then you need to construct your own list or collection class.
But if this is ok, then you can "call" the delegates in a given delegate's invocation list like this:
public delegate void MessageArrivedHandler(MessageBase msg);
public class MyClass
{
public event MessageArrivedHandler MessageArrivedClientHandler;
public void CallEachDelegate(MessageBase msg)
{
if (MessageArrivedClientHandler == null)
return;
Delegate[] clientList = MessageArrivedClientHandler.GetInvocationList();
foreach (Delegate d in clientList)
{
if (d is MessageArrivedHandler)
(d as MessageArrivedHandler)(msg);
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0]();
pd[1]();
}
public delegate void delegates();
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1()
{
MessageBox.Show("1");
}
public static void p2()
{
MessageBox.Show("2");
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0](1);
pd[1](2);
}
public delegate void delegates(int par);
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1(int par)
{
MessageBox.Show(par.ToString());
}
public static void p2(int par)
{
MessageBox.Show(par.ToString());
}
}
}