Understanding generics and Func arguments - c#

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);
}
}
}

Related

What interface type is suited for implementing strategy with different signature?

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);
}
}

How implement a delegation pattern in c# using delegates?

I want to implement delegation pattern using delegates
public class Cat {
private delegate void SoundDelegate();
private SoundDelegate sound;
public Cat() {
sound = new SoundDelegate(SomeClass.DoSound1);
}
public void DoSound() {
sound();
}
}
public class PussyCat {
private delegate void SoundDelegate();
private SoundDelegate sound;
public PussyCat() {
sound = new SoundDelegate(SomeClass.DoSound2);
}
public void DoSound() {
sound();
}
}
public class SomeClass {
public static void DoSound1() {
Console.WriteLine("Sound 1");
}
public static void DoSound2() {
Console.WriteLine("Sound 2");
}
}
Does this code impelement the delegation pattern? I mean can I use delegates for implement delegation pattern or this way is incorrect.
And if the previous example is correct and I can use delegates to implement the delegation pattern and implement the observer pattern, then what is the difference between the observer pattern and the delegation pattern and what is similar?
The difference between delegation and observer patterns is a level of control your class has over the delegate/observer.
In case of delegate, it's assumed that your class has full control over how delegated class should be used. The observable class has no idea of how exactly it would be used by other classes.
It's also often assumed that observable class could have any number of observers while delegate is usually one.
I also simplified the code provided trying to avoid unnecessarily class PussyCat, so the original class could be configured to use any delegate in runtime.
You can also find CatObservable class to understand the idea of observable-observer implementation.
class Program
{
static void Main(string[] args)
{
Cat cat1 = new Cat(SomeClass.DoSound1);
Cat cat2 = new Cat(SomeClass.DoSound2);
CatObservable cat3 = new CatObservable();
cat3.Sound += Cat3_Sound;
cat3.Sound += (object sender, EventArgs e) => { SomeClass.DoSound1(); } ;
cat3.Sound += (object sender, EventArgs e) => { SomeClass.DoSound2(); };
}
private static void Cat3_Sound(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
public class Cat
{
public delegate void SoundDelegate();
public SoundDelegate Sound { get; set; }
public Cat(SoundDelegate soundDelagate)
{
Sound = soundDelagate;
}
protected void DoSound()
{
if (Sound!=null)
Sound();
}
}
public class CatObservable
{
public event EventHandler Sound;
public CatObservable()
{
}
protected void DoSound()
{
if (Sound != null)
Sound(this, EventArgs.Empty);
}
}
public class SomeClass
{
public static void DoSound1()
{
Console.WriteLine("Sound 1");
}
public static void DoSound2()
{
Console.WriteLine("Sound 2");
}
}

How to define a static function with a generic return type meant to be overriden

I am trying to do something so convoluted it's hurting my brain. So please, if you can think of a better way of doing it than what I'm asking for, I'm all ears!
Essentially I have a class, ClientSession, and this class accepts messages over tcp and exposes them through an OnMessageReceived event. I am trying to tell the ClientSession to parse the message before exposing it in the event using a MessageParser class, passed as a generic parameter. I want to use a static method to avoid instantiating objects for nothing. I also want anyone else to be able to create their own message parser that spits out whatever Type they want.
Essentially, I need to
Guarantee to the ClientSession class that it can call TryParse() on the generic type I pass it during instantiation.
implement TryParse() as a static method
Like this
public static abstract class MessageParser<TMessage>
{
public static abstract TMessage TryParse(byte[] bytes);
}
Then someone else could define their own parser:
public static class ProtoParser : MessageParser<ProtoMessage>
{
public static ProtoMessage TryParse(byte[] bytes)
{
do some stuff...
return new ProtoMessage;
}
}
and finally:
public class ClientSession<TParser>
{
public void OnMessageReceived(Object sender, MessageEventArgs e)
{
return TParser.TryParse(e.bytes);
}
{
I know that static and abstract together is impossible, but you get the idea.
I have a gut feeling that I'm just approaching this wrong. Thanks in advance!
See here for why your current approach will not work and cannot work.
Some alternatives:
Passing an instance of a parser
public abstract class MessageParser<TMessage>
{
public abstract TMessage TryParse(byte[] bytes);
}
public class ProtoParser : MessageParser<ProtoMessage>
{
public override ProtoMessage TryParse(byte[] bytes)
{
return null;
}
}
public class ClientSession<TParser, TMessage> where TParser : MessageParser<TMessage>
{
TParser _parser;
public ClientSession(TParser parser)
{
_parser = parser;
}
public TMessage OnMessageReceived(Object sender, MessageEventArgs e)
{
return _parser.TryParse(e.bytes);
}
}
And using it:
var cs = new ClientSession<ProtoParser, ProtoMessage>(new ProtoParser());
Use instances of parsers created inside ClientSession
public abstract class MessageParser<TMessage>
{
public abstract TMessage TryParse(byte[] bytes);
}
public class ProtoParser : MessageParser<ProtoMessage>
{
public override ProtoMessage TryParse(byte[] bytes)
{
return null;
}
}
public class ClientSession<TParser, TMessage> where TParser : MessageParser<TMessage>, new()
{
TParser _parser = new TParser();
public TMessage OnMessageReceived(Object sender, MessageEventArgs e)
{
return _parser.TryParse(e.bytes);
}
}
And using it:
var cs = new ClientSession<ProtoParser, ProtoMessage>();
Passing a method to ClientSession
public static class ProtoParser
{
public static ProtoMessage TryParse(byte[] bytes)
{
return null;
}
}
public class ClientSession<TMessage>
{
Func<byte[], TMessage> _parser;
public ClientSession(Func<byte[], TMessage> parser)
{
_parser = parser;
}
public TMessage OnMessageReceived(Object sender, MessageEventArgs e)
{
return _parser(e.bytes);
}
}
And then using it:
var cs = new ClientSession<ProtoMessage>(ProtoParser.TryParse);

detect when "control flow" exits class

Assume I have a code:
class Module1 {
public static void Main(string[] args) {
Module1.level1();
}
public static void level1() {
Module1.level2();
}
public static void level2() {
Module2.level1();
}
}
[DetectWhenFlowExitsClass] // <-- note aspect
class Module2 {
public static void level1() {
Module2.level2();
}
public static void level2() {
Module2.level3();
}
public static void level3() {
throw new SystemException("oops");
}
}
After calling Main() I get a stacktrace:
Unhandled Exception: System.SystemException: oops
at Test.Module2.level3()
at Test.Module2.level2()
at Test.Module2.level1()
at Test.Module1.level2()
at Test.Module1.level1()
at Test.Module1.Main(String[] args)
Question
How to write aspect which detects moment when "control flow" exits code of class Module2?
That is, when Test.Module2.level1() finishes its work [here, due to exception].
Exist any shortcuts for this in PostSharp?
The most basic way would be to use OnMethodBoundaryAspect, which allows you to handle the method entry and method exit advices. You will need to count number of method of each particular class on the stack and when this count goes from 1 to 0, the control is leaving methods of the aspected class.
Here is the sample aspect code:
[Serializable]
public class DetectWhenFlowExitsClass : OnMethodBoundaryAspect
{
[ThreadStatic] private static Dictionary<Type, int> stackCounters;
private Type declaringType;
public override bool CompileTimeValidate(MethodBase method)
{
declaringType = method.DeclaringType;
return true;
}
private void EnsureStackCounters()
{
if (stackCounters == null)
stackCounters = new Dictionary<Type, int>();
}
public override void OnEntry(MethodExecutionArgs args)
{
EnsureStackCounters();
int counter;
stackCounters.TryGetValue(declaringType, out counter);
stackCounters[declaringType] = ++counter;
}
public override void OnExit(MethodExecutionArgs args)
{
EnsureStackCounters();
int counter;
stackCounters.TryGetValue(declaringType, out counter);
stackCounters[declaringType] = --counter;
if (counter == 0)
Console.WriteLine("Control leaving class {0}", declaringType.Name);
}
}
You will probably need to tinker with this aspect implementation a bit, but it works in basic situations.

Delegate Array in C#

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());
}
}
}

Categories