0

Lets say I have a class A which is going to be compiled into a dll to be used later. But I kind of know that later, some methods of class B which I am not aware of its type must be called in A class. The only clue is the name of the methods.

Lets say this is class A:

public class A
{
    A(Object instanceOfClassB)
    {
          //stuff...
    }

    public void SendProcessedString()
    {
         //some strings has been processd, I know that class B is going
         //to have a public method like ReceiveData(string data){/*---*/}
         instanceOfClassB.ReceiveData(data);
    }
}

Lets say this is class B, happen to be a WinForm:

public B : Form
{
     public void ReceiveData(string data)
     {
          textBox.Append(data + Environment.NewLine);
     }
}

Is such approach possible/recommended?

RE6
  • 2,684
  • 4
  • 31
  • 57
Dumbo
  • 13,555
  • 54
  • 184
  • 288

5 Answers5

5

Yes, this is possible using the dynamic keyword (in C# 4.0 or higher). Check the MSDN documentation for more info.

However, this leads to incredibly loose programming and can cause runtime issues that are difficult to debug. You're much better off creating an interface that class B will implement.

public class A
{
    A(IDataReceiver instanceOfClassB)
    {
          //stuff...
    }

    public void SendProcessedString()
    {
         //some strings has been processd, I know that class B is going
         //to have a public method like ReceiveData(string data){/*---*/}
         instanceOfClassB.ReceiveData(data);
    }
}

public B : Form, IDataReceiver
{
     public void ReceiveData(string data)
     {
          textBox.Append(data + Environment.NewLine);
     }
}

public interface IDataReceiver
{
    void ReceiveData(string data);
}
BJ Myers
  • 6,617
  • 6
  • 34
  • 50
  • Are you stealing my answer? I stole yous as well ;) – Yogee Feb 19 '15 at 21:25
  • yeah....I was looking for dynamic...had read about it somewhere long time ago. Interface I know by heart lol...but the point is in my case I am not able to tell others are going to implement from the interface...so I go with dynamic and hope for the best. – Dumbo Feb 19 '15 at 21:28
  • @SaeidYazdani If you're not sure whether class B will implement the interface, you can check for it by using `instanceOfClassB is IDataReceiver`. This way you can take an `object` in the class B constructor, check to see if it implements the interface, and if so, cast it to an `IDataReceiver` and send the data. Dan-o's answer with callbacks and/or events may also be helpful. – BJ Myers Feb 19 '15 at 21:33
2

You should be using interface. You class B must implement "MyInterface" interface and "MyInterface" should have method which are are expecting A to call.

public class A
{
    A(MyInerface instanceOfClassB)
    {
          //stuff...
    }

    public void SendProcessedString()
    {
         //some strings has been processd, I know that class B is going
         //to have a public method like ReceiveData(string data){/*---*/}
         instanceOfClassB.ReceiveData(data);
    }
}

If it is not possible to implement interface at class B, you need to use reflection. See here (How to use reflection to call method by name) on how to call a method from a Type (so you will have to pass the type in constructor of A.

Community
  • 1
  • 1
Yogee
  • 1,412
  • 14
  • 22
  • Also, with .NET 4.0, you can use "dynamic" keyword to make your reflection code look good :) – Yogee Feb 19 '15 at 21:23
  • Dynamic is a very bad practice for type safe languages. You should use `interfaces` and other `polymorphic` tools instead – RE6 Feb 19 '15 at 21:26
  • That's what I suggested, Dynamic is alternate of Reflection. My bad - I edited my comment to indicate that. – Yogee Feb 19 '15 at 21:27
2

It sounds you need to use an interface. A little information about interfaces can be found here.

Basically you want to create an interface and get it as a parameter for class A and implement it in class B:

interface IDataReceiver
{
    void ReceiveData(string data);
}

then class B decleration will look like:

public B : Form, IDataReceiver

And class A` constructor:

A(IDataReceiver dataReceiver)
{
    //stuff...
}
RE6
  • 2,684
  • 4
  • 31
  • 57
2

Another option here would be to use events. Have your raise an event instead of invoking the callback.

excuse my C#, I'm a little rusty

public class classA {
    public event DataReceived(string data);

    public void SendProcessedString() {
        // you got var data from somewhere
        DataReceived(data)
    }
}

Then subscribe to that event from your classB

// classB setup code or initializer:
instanceA.DataReceived += dataReceivedHandler;

private void dataReceivedHandler(string data) {
    // do something with the data.
}
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • Good answer. The only hiccup is if the DLL that contains class A references the DLL that contains class B - in that case, class B can't know about class A to subscribe to the callback. – BJ Myers Feb 19 '15 at 21:36
  • @nintendojunkie: Absolutely. I would think though that in that situation the type definition of classB would be known to classA. – Sam Axe Feb 19 '15 at 21:39
1

Yet another method is to use a proper callback - only if a single subscriber is guaranteed. If you need multiple subscribers use an event.

public class classA {
    public Action<string> DataReceivedCallback = null;

    public void SendProcessedString() {
        if (null != DataReceivedCallback) { DataReceivedCallback.Invoke(data); }
    }
}

somewhere in classB

instanceA.DataReceivedCallback = new Action<string>(dataReceivedHandler);

private void dataReceivedHandler(string data) {
    // do something with the data.
}
Sam Axe
  • 33,313
  • 9
  • 55
  • 89