Consider the following console program. It has four classes: Program, Attacker, Defender, and Helper. I want to remove the logic from the Defender class and use delegates to call helpers. I've spent some time on this and can't quite get it.
Where do I declare my delegate: in Program or in Defender?
Where do I instantiate my delegate: in Program or in Defender?
Where do I subscribe my delegate: in Program or in Helper?
I could post my attempts but it wouldn't be helpful.
using System;
namespace Delegates19
{
public class Program
{
static void Main(string[] args)
{
Attacker a = new Attacker();
string weapon = "sword";
a.Attack(weapon);
Defender d = new Defender();
d.Help(weapon);
weapon = "spear";
a.Attack(weapon);
d.Help(weapon);
}
}
public class Attacker
{
public void Attack(string s)
{
Console.WriteLine($"Attacker attacks with {s}");
}
}
public class Defender
{
public void Help(string s)
{
Console.WriteLine($"Defender is attacked with {s} and calls for help");
if (s == "sword")
Helper.Knight();
if (s == "spear")
Helper.Bowman();
}
}
public class Helper
{
public static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
public static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
}
I'm really not sure why you would want to do this, but these both work and might give you ideas.
Unless I understand your need for events/delegates I actually prefer your code over these.
Delegates:
public class Defender
{
private static Action SwordAction = Helper.Knight;
private static Action SpearAction = Helper.Bowman;
public void Help(string s)
{
Console.WriteLine($"Defender is attacked with {s} and calls for help");
if (s == "sword")
SwordAction();
if (s == "spear")
SpearAction();
}
}
public static class Helper
{
public static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
public static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
Events:
static void Main(string[] args)
{
using (var d = new Defender())
{
d.GetHelp += StandardDefenseHelp.Defender_GetHelp;
d.Help("sword");
d.Help("spear");
}
}
public class Defender : IDisposable
{
public event EventHandler<string> GetHelp;
private void RaiseGetHelp(string weapon) => GetHelp?.Invoke(this, weapon);
public void Help(string weapon)
{
Console.WriteLine($"Defender is attacked with {weapon} and calls for help");
RaiseGetHelp(weapon);
}
public void Dispose()
{
GetHelp = null;
}
}
public static class StandardDefenseHelp
{
public static void Defender_GetHelp(object sender, string weapon)
{
if (weapon == "sword")
Knight();
if (weapon == "spear")
Bowman();
}
private static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
private static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
Important: events often are the cause of memory leaks, that's why Defender is now disposable.
The above design could be useful if you have multiple "DefenseHelp" types and other things also should happen when a defender needs help that the defender itself needs to know nothing about.
But I'd only do this if it gave some benefit. I believe in the KISS development methodology.
Related
class Program
{
static void Main(string[] args)
{
//I want to call the bird method here
}
public void bird(Program program)
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
How do I call bird in the main, I also tried to call the method from a object of the class but that didn't work
Does it even make sense to do this (I try to avoid static methods as much as possible).
If a method can be made static without changing the code, you should make it static. To answer your question though, you can create an instance of Program in your Main function and call the non-static methods through it.
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.bird();
}
public void bird()
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
Could do something like this
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var p = new Program();
p.bird(p);
}
public void bird(Program program)
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
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");
}
}
I have a question that may be silly, but I'm new to C#, so pardon my insolence. I am wondering whether it is possible for a function to refer to an instance, which has been created by another function.
I am including an exemplary code to illustrate what I mean:
class Program
{
static void Main(string[] args)
{
Instantiator.Instantiate();
Referent.Refer(instance);
Console.ReadLine();
}
}
public class Instance
{
public void OnInstantiated()
{
Console.WriteLine("I have been instantiated.");
}
public void OnReferred()
{
Console.WriteLine("I have been referred to.");
}
}
public class Instantiator
{
public static void Instantiate()
{
Instance instance = new Instance();
instance.OnInstantiated();
}
}
public class Referent
{
public static void Refer(Instance instance)
{
if(instance != null)
{
instance.OnReferred();
}
else
{
Console.WriteLine("No instance to refer to.");
}
}
}
What could I use to be able to refer to the "instance" instance (which is created by the Instantiator.Instantiate function) in the Referent.Refer function?
Thanks in advance for your pertinent comments!
Make Instantiator return the class when done
public class Instantiator
{
public static Instance Instantiate()
{
Instance instance = new Instance();
instance.OnInstantiated();
return instance;
}
}
class Program
{
static void Main(string[] args)
{
var instance = Instantiator.Instantiate();
Referent.Refer(instance);
Console.ReadLine();
}
}
The pattern Instantiate() is doing is often called the "Factory Pattern"
Another option you could use is the Singleton pattern. If you also need your instance to be only one, you can give the responsibility to create a new instance and return it afterwards to the class itself.
class Program
{
static void Main(string[] args)
{
Instance.Instantiate();
Referent.Refer(Instance.GetInstance());
Console.ReadLine();
}
}
public class Instance
{
private static Instance myInstance;
public void OnInstantiated()
{
Console.WriteLine("I have been instantiated.");
}
public void OnReferred()
{
Console.WriteLine("I have been referred to.");
}
public static void Instantiate()
{
myInstance = new Instance();
myInstance.OnInstantiated();
}
public static Instance GetInstance()
{
return myInstance;
}
}
public class Referent
{
public static void Refer(Instance instance)
{
if (instance != null)
{
instance.OnReferred();
}
else
{
Console.WriteLine("No instance to refer to.");
}
}
}
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);
}
}
}
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.