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();
}
}
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.
How can I call method whithout creating class.
Example
public class1 {
class2 = new class2();
int size;
private void method() {
size = class2.size;
}
}
public class2 {
private void method() {
//call method from class1
}
}
You can do that making the method of class1 static (add the static reserved word before private)
That way you can call the method as class1.method();
Hope this is what you are looking for!
I mean it:
public Class1 {
Class2 class2 = new Class2();
public int size;
public Class1() {
class2.handler += method1;
}
private void method1() {
size = class2.size;
}
}
public Class2 {
...
public int size;
public delegate void Handler();
public Handler handler;
private void method2() {
size = UpdateSize();
handler?.Invoke();
}
private int UpdateSize() {
...
}
}
Here is the code I currently have, the question follows after:
class Program
{
static void Main(string[] args)
{
var obj1 = new A();
obj1.DoIt();
obj1.SetFlyBehavior(new BehaviorB());
obj1.DoIt();
string input = Console.ReadLine();
}
};
class BaseOfA
{
protected ObjectBehavior behavior;
public void DoIt()
{
behavior.DoIt();
}
public void SetBehavior(ObjectBehavior ob) {
behavior = ob;
}
};
class A : BaseOfA {
public A() {
behavior = new BehaviorA();
}
}
interface ObjectBehavior {
void DoIt();
}
class BehaviorA : ObjectBehavior {
void ObjectBehavior.DoIt() {
Console.WriteLine("Behavior: A");
}
}
class BehaviorB : ObjectBehavior {
void ObjectBehavior.DoIt() {
Console.WriteLine("Behavior: B");
}
}
Now my question is, in this case, how am I going to make it work so that I can assign both BehaviorA and BehaviorB to instance obj1 as long as they implement ObjectBehavior?
You are calling obj.SetFlyBehaviour this method is not defined anywhere. The method you define on BaseOfA is called SetBehaviour. Once that is fixed the code you gave compiles fine for me
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");
}
}
}
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()