tags:

views:

80

answers:

3

Hi,
In my app, I wanted to let class B get some information from class A but as A instantionates B, B has no reference to A (intentionally). I have never used events for that purpose so I am not sure whether its correct, but it works:

class A
{
 public delegate bool GetFromB();
 public event GetFromB GetDataFromB;
...

//get data from B without having an access to it
bool Result=GetDataFromB();
}

class B
{
A a=new A();
A.GetDataFromB=new A.GetFromB(DO_THAT);

public bool DO_THAT()
{
 ...
return true;     //and that is it, it will return to event caller
}

}
+2  A: 

It'll certainly work, and that approach is used in a few places in the core framework - AssemblyResolve etc. Alternative approaches here:

  • if it is used by a method, pass it into the method as a callback delegate. Same approach, but simply not exposed as an event
  • ditto, but with an interface

but it'll work that way. It isn't unheard of. Code tweaks, though:

A a=new A();
a.GetDataFromB=+new A.GetFromB(DO_THAT);

you subscribe on the instance (unless it is static), and need +=, not =.

Also: consider using Func<bool> rather than declaring your own delegate type.

Marc Gravell
Thanks, yes it is air code, typo.
Tomas
+1  A: 

Don't do that. Events implies that multiple listeners can be used, and it looks like you are not handling return values from multiple listeners. You can do that by traversing myevent.GetInvocationList() and invoke each listener separately.

Use a simple delegate instead:

class A
{
   public delegate bool GetFromB();
   public GetFromB GetDataFromB { get; set; }
}

The other standard way is to have event arguments that provide a property for return value.

class MyEventArgs : EventArgs
{
   public bool ReturnValue {get; set; }
   // and something more here.
}

public class A
{
   public event EventHandler<MyEventArgs> MyEvent;
}
jgauffin
That changes nothing. Even as a delegate it is multicast.
Marc Gravell
How can a delegate assigned by a property be multicast? The second example was just to illustrate a better way to handle return values if multicast delegates (/events) is what he want's to use.
jgauffin
A: 

As you wrote, A currently instanciates B so, you should not change this by creating an instance of A in B.

If B needs several different data from A, you can let A realize some IBNeededData interface. If B needs only one call on A, the straight forward solution would be a callback method.

Edit

Here's a sample for the callback. (Hope you are fine with the lambda expression to provide the data from A.)

   [TestClass]
   public class UnitTest1 {
      class A {
         public void DoWork() {
            B b = new B();

            //b.GetData = () => "Some data";
            Func<string> callback = new Func<string>(this.GetBData);
            b.GetData = callback;

            b.DoBWork();
         }
         private string GetBData() {
            return "Some data";
         }
      }
      class B {
         public Func<string> GetData { get; set; }
         public void DoBWork() {
            string data = GetData();
            Console.WriteLine("Working with {0}", data);
         }
      }

      [TestMethod]
      public void TestMethod1() {
         A a = new A();
         a.DoWork();
      }
   }

Greets Flo

Florian Reischl
Thanks, not sure how to implement the callback here? Not so experienced yet :(
Tomas
@Tomas: I changed my post and added a sample for the callback.
Florian Reischl
Thank you! I have never used lamda expression but I know they exist :)
Tomas
Lambda expressions are a shorted way to work with delegates. I changed my post again to show the classic approach.
Florian Reischl