I want to wait on the GetValues.Get Method and return the values syncronously to the caller. The ServerDataProvider, BookDataFetcher classes are external to mycode, on which I have no control.
Any help on how to achieve this is much appreciated.
namespace Test {
class Program
{
static void Main(string[] args)
{
GetValues val = new GetValues();
val.Get("BOOKS", DataHandler);
Console.ReadKey();
}
static void DataHandler(IList<string> values) {
}
}
class GetValues
{
public delegate void DataHandler(IList<string> values);
public event DataHandler OnReceiveDataHandler;
public void Get(string colName, DataHandler handler)
{
OnReceiveDataHandler += handler;
GetDataFromServer svr = new GetDataFromServer();
svr.OnReceiveDataHandler += OnReceiveData;
svr.GetData(colName);
}
// Callback Handler
private void OnReceiveData(IList<string> values) {
OnReceiveDataHandler(values);
}
}
class GetDataFromServer
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
internal void GetData(string columnName)
{
ServerDataProvider datafetcher = new ServerDataProvider();
datafetcher.OnReceiveDataHandler += OnReceiveData;
Task.Factory.StartNew(() => datafetcher.GetDataFromServer(columnName));
}
// Callback Handler
private void OnReceiveData(IList <string> values) {
OnReceiveDataHandler(values);
}
}
class ServerDataProvider
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
public void GetDataFromServer(string columnName)
{
BookDataFetcher b = new BookDataFetcher();
b.OnReceiveDataHandler += OnReceiveData;
Task.Factory.StartNew(() => b.GetBookData(columnName));
}
// Calback Handler
private void OnReceiveData(IList<string> values)
{
OnReceiveDataHandler(values);
}
}
class BookDataFetcher
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
public void GetBookData(string col)
{
Thread.Sleep(5000);
OnReceiveDataHandler(new List<string> {"Book1", "Book2"});
}
}
}
What you are asking can be achieved using MethodImplAttribute
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void MethodA()
Related
I am making a game using Unity and creating a simple event system for it. The system allows subscribing to events with a callback delegate.
The code for the system is here:
public static class Events {
#region fields
public delegate void EventCallback();
public static Dictionary<Event, EventCallback> events;
public enum Event {
PlayerDied,
EnterGoal,
ExitGoal
}
#endregion
static Events() {
Reset();
}
public static void Reset() {
events = new Dictionary<Event, EventCallback>();
}
public static void SubscribeToEvent(EventCallback callback, Event type) {
if (!events.ContainsKey(type)) {
events.Add(type, callback);
} else {
events[type] += callback;
}
}
public static void OverrideSubscription(EventCallback callback, Event type) {
if (!events.ContainsKey(type)) {
events.Add(type, callback);
} else {
events[type] = callback;
}
}
public static void UnsubscribeFromEvent(EventCallback callback, Event type) {
if (events.ContainsKey(type)) {
events[type] -= callback;
}
}
public static void FireEvent(Event type) {
if (!events.ContainsKey(type)) {
return;
}
events[type]?.Invoke();
}
}
My problem is this:
Quite often in the game the object which subscribes to some event will be destroyed (and therefore nullified) but the callbacks are still called.
To demonstrate this I created tests for it. The 2 tests below fail.
[Test]
public void CallbackIsNotCalledAfterReassigning() {
Events.SubscribeToEvent(callbacks.A, Events.Event.PlayerDied);
// Reassign
callbacks = new CallbackContainer();
Events.FireEvent(Events.Event.PlayerDied);
Assert.AreEqual(0, callbacks.a, "Test function was called after reassigning");
Assert.AreEqual(0, a, "Old instance method is still being called");
}
[Test]
public void CallbackIsNotCalledAfterNullifying() {
Events.SubscribeToEvent(callbacks.A, Events.Event.PlayerDied);
// Nullify
callbacks = null;
Events.FireEvent(Events.Event.PlayerDied);
Assert.AreEqual(0, a, "Test function was not called");
}
And the CallbackContainer class is here:
public class CallbackContainer {
public int a, b, c;
public CallbackContainer() {
int a = 0;
int b = 0;
int c = 0;
}
public Action TestFunction;
public void A() {
EventsTest.a++;
a++;
}
public void B() {
EventsTest.b++;
b++;
}
public void C() {
EventsTest.c++;
c++;
}
}
Is there a workaround for this problem? Is there a better and more correct way to creating an event system?
Any help or advice is appreciated.
I had forgotten about Unitys own delegate OnDestroy which is called before an object is destyroyed or before another scene is loaded.
What is the problem in this code?
namespace ConsoleApplication1
{
public delegate void del();
class Program
{
static void Main(string[] args)
{
del d = new del(add);
d += sub;
}
public static void add()
{
Console.WriteLine("add");
}
public static void sub()
{
Console.WriteLine("Sub");
}
}
}
You need to invoke your delegate:
class Program
{
static void Main(string[] args)
{
del d = new del(add);
d += sub;
d.Invoke();
}
public static void add()
{
Console.WriteLine("add");
}
public static void sub()
{
Console.WriteLine("Sub");
}
}
}
Is there any way to initialise a delegate with a string? I.e. you won't know the name of the function that needs to be called at runtime? Or I'm guessing there is a better way of doing this?
delegate void TestDelegate(myClass obj);
void TestFunction()
{
TestDelegate td = new TestDelegate(myFuncName); // works
TestDelegate td = new TestDelegate("myFuncName"); // doesn't work
}
Update
Is is the code I currently have which is not working
class Program
{
static void Main(string[] args)
{
Bish b = new Bish();
b.MMM();
Console.Read();
}
}
class Bish
{
delegate void TestDelegate();
public void MMM()
{
TestDelegate tDel = (TestDelegate)this.GetType().GetMethod("PrintMe").CreateDelegate(typeof(TestDelegate));
tDel.Invoke();
}
void PrintMe()
{
Console.WriteLine("blah");
}
}
You can create a dynamic delegate this way
class Bish
{
delegate void TestDelegate();
delegate void TestDelegateWithParams(string parm);
public void MMM()
{
TestDelegate tDel = () => { this.GetType().GetMethod("PrintMe").Invoke(this, null); };
tDel.Invoke();
TestDelegateWithParams tDel2 = (param) => { this.GetType().GetMethod("PrintMeWithParams").Invoke(this, new object[] { param }); };
tDel2.Invoke("Test");
}
public void PrintMe()
{
Console.WriteLine("blah");
}
public void PrintMeWithParams(string param)
{
Console.WriteLine(param);
}
}
I have a class with a method in which a string will be passed. That method will do some things to that string and it then passes the string to a certain object which can do other things with the string.
So it basically looks like this:
class Main
{
public Main()
{
strClass str = new strClass(this);
}
public function handler ( )
{
console.log("No string is passed yet, but this method is called from receiveData()");
}
}
class strClass
{
object handler;
public strClass ( handler )
{
// save the object
this.handler = handler;
}
public receiveData ( string str )
{
// This method does some stuff with the string
// And it then passes it on to the supplied object (handler) which will do
// the rest of the processing
// I'm calling the "handler" method in the object which got passed in the
// constructor
Type thisType = this.handler.GetType();
MethodInfo theMethod = thisType.GetMethod("handler");
theMethod.Invoke(this.handler, null);
}
}
Now this code works good, with the reflection stuff. But i was wondering, shouldn't this be possible (and maybe even better?) with delegates?? If so, how can i implement this by using a delegate instead?
Couldn't you use interfaces instead:
interface IStringHandler {
void HandleString(string s);
}
class strClass
{
IStringHandler handler = null;
public strClass(IStringHandler handler)
{
this.handler = handler;
}
public void ReceiveData(string s)
{
handler.HandleString(s);
}
}
class Main : IStringHandler
{
// Your code
}
A delegate is a better option here.
class Main
{
public Main()
{
StrClass str = new StrClass(this.Handler);
}
public void Handler ( )
{
//called from recieve data
}
}
class StrClass
{
readonly Action _handler;
public StrClass ( Action callback)
{
// save the object
this._handler = callback;
}
public void receiveData( string str )
{
this._handler();
}
}
You can do it with an Action like this:
class Main
{
public Main()
{
strClass str = new strClass(newString =>
{
console.log("This string I got back: " + newString);
});
}
}
class strClass
{
Action<string> callback;
public strClass (Action<string> callback)
{
// save the action
this.callback = callback;
}
public receiveData ( string str )
{
// Do something with the string
callback(str);
}
}
Even nicer than using delegates whould be using the
Chain of Responsibility design pattern, which does exactly what you need :).
Firstly, if you must call an unknown method by name, use dynamic - it is heavily optimised for this (although still not a great idea):
((dynamic)handler).handler(); // but please don't use this! see below
However, I would instead look at either an Action<string> (or maybe Func<string,string>), or an interface with a known method on it.
Basically, you want to change how your StrClass object react to data begin received. Sounds like events to me.
something like this, where you have handling methods both in the Main and in a generic HandlerObject:
class StrClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = null;
public void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
private string receivedString;
public string ReceivedString
{
get;
set
{
string oldStr = receivedString;
receivedString = value;
PropertyChanged(receivedString, new PropertyChangedEventArgs("ReceivedString"));
}
}
public void receiveData(string str)
{
//event fires here
ReceivedString = str;
}
}
class HandlerObject
{
public void HandlerMethod1(string s)
{
//magic
}
public void HandlerMethod2(string s)
{
//different kind of magic
}
}
class Program
{
static void HandlerMethod3(string s)
{
//another kind of magic!
}
static void Main(string[] args)
{
StrClass class1 = new StrClass();
StrClass class2 = new StrClass();
StrClass class3 = new StrClass();
HandlerObject handler = new HandlerObject();
class1.PropertyChanged += (s, e) => { handler.HandlerMethod1(s.ToString()); };
class2.PropertyChanged += (s, e) => { handler.HandlerMethod2(s.ToString()); };
class3.PropertyChanged += (s, e) => { HandlerMethod3(s.ToString()); };
}
}
Having an event like this:
class ABC
{
delegate bool X (int a);
event X eventX;
}
ABC.eventX+=someMethod; //works
I assume the delegate is then created implicitly by compiler?
Yes, prior to .NET 2 you had to manually specify it:
ABC.eventX+=new X(someMethod);
But it is now created implicitly with this syntax:
ABC.eventX+=someMethod;
Yes, it's automatically created.
For example:
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
(new Program()).Entrance();
}
public void Entrance()
{
ABC a = new ABC();
a.eventX += callback;
}
protected bool callback(int a)
{
return true;
}
}
class ABC
{
public delegate bool X(int a);
public event X eventX;
}
}
The Program class will be this if you see in reflector:
internal class Program
{
// Methods
protected bool callback(int a)
{
return true;
}
public void Entrance()
{
ABC a = new ABC();
a.eventX += new ABC.X(this.callback);
}
private static void Main(string[] args)
{
new Program().Entrance();
}
}