C# user defined callbacks to a method in a different class - c#

I've been looking for several days for the solution to a trivial problem in C or C++ but seemingly impossible in C#.
Another programmer creates class A. An event handler method in class A needs to call a method in my class B to process the event. Depending on the type of event, that method in class B needs to callback a method in class A, and that method has an arbitrary name or may not even exist.
This is simple in C; you just have a pointer to the callback function and call it indirectly if it isn't null. I don't know how to do indirect method calls in C#. Here's an example of some code illustrating the problem.
public class A: ZZZ { // this class is NOT under my control
private b = new B(this);
public void myCallback(C x) {
// do something
}
// Elsewhere in the application expects a protected
// override method to exist in *this* class A to handle
// an event. But we want a method in class B to handle
// it and then call myCallback depending on the type of event
protected override void handle_some_event(event e) {
// doesn't work -- how do I pass a "pointer" to the callback??
b.handle_event(e, myCallback);
}
}
public class B { // this class IS under my control
private A base;
public B(A a) {
base = a; // allows for calling methods in class A from class B
}
public handle_event(event e, ??? callback pointer ??? cback) {
// do stuff...
// then do the callback
// cback(); // this won't work
base.myCallback(); // this WILL work but only if I hard-code "myCallback"
}
}
The problem is that class B is the one I'm writing, and class A is authored by someone else who will be using my class B. That someone else has the option of not defining a callback at all, or creating one with any arbitrary name. Class B needs to know somehow what that is and how to access it. In C or C++ the other programmer could simply pass a pointer to his callback function. Is that possible in C#?

You want to pass an Action<T> to the handle_some_event you can do that like this:
public handle_some_event(event e, Action<C> cback)
{
// Do stuff
if(cback != null)
cback(myC);
}
Your class B in fact doesn't need to know anything at all about class A, it just needs an Action delegate to execute, the rest is irrelevant.

You can use Action delegate to refer to the callback.
Check this URL for more info: http://msdn.microsoft.com/en-us/library/018hxwa8.aspx
Change you class B to :
public class B {
private A base;
public B(A a) {
base = a; // allows for calling methods in class A from class B
}
//#################### NOTE THE CHANGE HERE ##################//
public handle_some_event(event e, Action<C> cback) {
// do stuff...
// then do the callback
cback(x); // this will work assuming you have x defined somewhere in B
}
}

Here is the solution I ended up with, based on the code in my initial post
public class A: ZZZ { // this class is NOT under my control
private b = new B(this);
b.UserCallback = myCallback;
static void myCallback(C x) {
// do something
}
// Elsewhere in the application expects a protected
// override method to exist in *this* class A to handle
// an event. But we want a method in class B to handle
// it and then call myCallback depending on the type of event
protected override void handle_some_event(event e) {
b.handle_event(e);
}
}
public delegate void usercallback(Z z); // declare OUTSIDE both classes
public class B { // this class IS under my control
public usercallback UserCallback = defaultCallback;
static void defaultCallback(Z z) { /* do nothing */ }
public handle_event(event e) {
// do stuff...
// then do the callback
UserCallback(z);
}
}
What got me stuck for a while is wrapping my head around the fact that a delegate declaration is analogous to a C function prototype, and that a delegate may be used as a declaration type in a class.

Related

C# Call function from another class

I think my question is best descirbed by a code snippet:
class A
{
public void FunctionToBeCalled();
}
class B
{
public void FunctionToBeCalledAfter();
}
Now, after a FunctionToBeCalledAfter() call, FunctionToBeCalled() needs to "know" it must be called. B cannot have an A member, but A can have a B member. Is there any way this can be implemented in C#?
Why i need this:
Class A is Application level on OSI stack. Classes B and C(unmentioned before) are Transport Level. C makes calls to FunctionToBeCalledAfter, and after this FunctionToBeCalled needs to be called. But sincer A is a higher level, B and C cannot depend(have a member A), i don't know how to call FunctionToBeCalled.
I see 2 ways to accomplish this, one easier but (arguably) less elegant, one a little more involved but (arguably) more elegant
The less elegant solution: Singleton
A Singleton pattern enforces that there can only ever be one instance of a class at any given time, this seems to line up with your description of A (which from here on out I'll call Foo, and I'll be calling B Bar). So let's implement it:
public class Foo
{
private static Foo _instance;
public static Foo Instance => _instance ?? (_instance = new Foo());
// Private constructor so no one else can instantiate Foo
private Foo() { }
public void FunctionToBeCalled() { /* your code here */ }
}
public class Bar
{
public void FunctionToBeCalledAfter()
{
// Your existing code here
Foo.Instance.FunctionToBeCalled();
}
}
Now, the problem here is if your requirements ever change and you need multiple Foos, that'll be quite a refactor to implement it. Another (larger) downside is that we explicitly reference (i.e depend on) Foo, which isn't great and a problem if Bar is inside a project/ library that cannot directly reference Foo. Luckily solution 2 fixes those problems:
The more elegant solution: Events
public class Foo
{
// We don't need Foo to be a singleton anymore
public void FunctionToBeCalled() { /* Your code here */ }
}
public class Bar
{
public delegate void FunctionToBeCalledAfterEventHandler();
public event FunctionToBecalledAfterEventHandler FunctionToBeCalledAfterEvent;
public void FunctionToBeCalledAfter()
{
// Your existing code here
OnFunctionToBeCalledAfterEvent(); // Fire the event
}
private void OnFunctionToBeCalledAfterEvent()
{
FunctionToBeCalledEvent?.Invoke();
}
}
Now, everywhere where you're creating an instance of Bar you need to have a reference to Foo and subscribe to the event like so:
// foo = instance of class Foo
var bar = new Bar();
// The compiler is smart enough to find out that 'FunctionToBeCalledAfterEvent'
// has the same signature as 'FunctionToBeCalledAfterEvent' and can call it directly
// If this just so happens to not be case, see second way to subscribe to events
bar.FunctionToBeCalledAfterEvent += foo.FunctionToBeCalled;
// Or
bar.FunctionToBeCalledAfterEvent += () => foo.FunctionToBeCalled();
Events are great
Class B can have an event that other parties can handle. At the end of B.FunctionToBeCalledAfter this event would be invoked. Anyone who registered for this event would then be notified. Usual boilerplate code involves one virtual method that invokes one event. It's the standard way of adding events. If there is no need for additional data in the event then EventArgs is used. If additional data is needed then you could replace EventArgs with EventArgs<YourData>, or as an alternative, introduce a class XxxArgs derived from EventArgs with this additional data.
Class B
{
public event EventHandler FinishedFunctionToBeCalledAfter;
protected virtual void OnFinishedFunctionToBeCalledAfter(EventArgs e)
{
EventHandler handler = FinishedFunctionToBeCalledAfter;
handler?.Invoke(this, e);
}
public void FunctionToBeCalledAfter()
{
...
OnFinishedFunctionToBeCalledAfter(EventArgs.Empty);
}
}
Now when class A gets a hold of an object of class B it would add its event handler to it:
class A
{
public void FunctionToBeCalled();
public void FinishedFunctionToBeCalledAfter(object source, EventArgs e);
public void IntroduceObject(B b)
{
b.FinishedFunctionToBeCalledAfter += FinishedFunctionToBeCalledAfter;
}
}
When this object b of class B should end its life class A must know about it so that it can remove its event handler:
b.FinishedFunctionToBeCalledAfter -= FinishedFunctionToBeCalledAfter;

limit method to only be called by a particular class

I want a particular method in one class to only be accessible by a particular class. For example:
public class A
{
public void LimitedAccess() {}
public void FullAccess() {}
}
public class B
{
public void Func()
{
A a = new A();
a.LimitedAccess(); // want to be able to call this only from class B
}
}
public class C
{
public void Func()
{
A a = new A();
a.FullAccess(); // want to be able to call this method
a.LimitedAccess(); // but want this to fail compile
}
}
Is there is a keyword or attribute that I can use to enforce this?
UPDATE:
Due to existing system complexity and time constraints, I needed a low impact solution. And I wanted something to indicate at compile time that LimitedAccess() could not be used. I trust Jon Skeet's answer that exactly what I had asked for could not be done in C#.
The question and Jon's answer are good for those who may run across this later. And the fact that this design smells can hopefully veer anyone away for choosing something like this as a desired a solution.
As mentioned in a comment, the C# friend conversation is useful reading if you are trying to solve a similar situation.
As for my particular solution: "why would A contain B's logic" (asked by #sysexpand in comments). That's the rub. B.Func() was called throughout the system I'm working on, but it primarily operated on a singleton of A. So what I ended up doing was moving B's Func() into A and making A.LimitedAccess() private. There were a few other details to work around, as there always are, but I got a low impact solution that gave me compile-time errors on callers to A.LimitedAccess().
Thanks for the discussion.
No. The only thing you could do would be to make LimitedAccess a private method, and nest class B within class A.
(I'm assuming you want all the classes in the same assembly. Otherwise you could put A and B in the same assembly, and C in a different assembly, and make LimitedAccess an internal method.)
Yes. What you are asking for is perfectly possible.
You can restrict access to methods and variables for a specific instance, by using an interface.
However, an interface alone cannot prevent someone from creating their own instance of the class, at which point they will have full access to that instance.
To do that, next you should nest it as a private class inside of another class in order to restrict access to the constructor.
Now you have a particular method in one class to only be accessible by a particular class.
In this example, only class B is ever able to access function LimitedAccess.
public interface IA
{
void FullAccess();
}
public class B
{
private class A : IA
{
public void LimitedAccess() {} //does not implement any interface
public void FullAccess() {} //implements interface
}
private A a = new A();
public IA GetA()
{
return (IA)a;
}
public void Func()
{
/* will be able to call LimitedAccess only from class B,
as long as everybody else only has a reference to the interface (IA). */
a.LimitedAccess();
}
}
//This represents all other classes
public class C
{
public void Func(IA ia)
{
ia.FullAccess(); // will be able to call this method
ia.LimitedAccess(); // this will fail to compile
}
}
public static class MainClass
{
public static void Main(string[] args)
{
B b = new B();
b.Func();
IA ia = b.GetA();
C c = new C();
c.Func(ia);
}
}
In case you just want to remind yourself (or team mates) to not call LimitedAccess everywhere, you could consider using explicit interface implementation or mark LimitedAccess as obsolete.
public interface IA
{
void LimitedAccess();
void FullAccess();
}
public class A : IA
{
private void LimitedAccess() { }
public void FullAccess() { }
void IA.LimitedAccess() => LimitedAccess();
void IA.FullAccess() => FullAccess();
}
public class B
{
public void Func()
{
IA a = new A();
a.LimitedAccess(); // want to be able to call this only from class B
}
}
public class C
{
public void Func()
{
A a = new A();
a.FullAccess(); // want to be able to call this method
a.LimitedAccess(); // -> fails to compile
}
}
Maybe this is a workaround.
Use the System.Runtime.CompilerServices and then you can either check the Name of the calling function and/or the file, in which the calling function is defined. If you have a class per file, the filename might be a substitude for the class name. Check it and block the call.
internal void MySecretFunction (string something,
[CallerMemberName] string memberName = null,
[CallerFilePath] string filePath = null,
[CallerLineNumber] int lineNumber = 0) {
if (!filePath.EndsWith(#"\goodClass.cs")) return;
// else do something
}
You could always see the calling type with a StackTrace.
Just note that when building in release mode, the call on the stack will get optimized, and its possible that the stack trace could return a completely different class, so just make sure to test it before you publish.
/// <summary>
/// Warning: Any class that calls this other than "B" will throw an exception.
/// </summary>
public void LimitedAccess()
{
if (new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType != typeof(B)) throw new Exception("Invalid Caller Type, B is only class able to call this method.");
}
Unfortunately you wont be able to know if its an error on compile time. Best you can do is throw an exception if it gets called, and add a comment warning people about it.
It is against OOP best practices to make such a design. Methods of classes are not supposed to be protected from being called.
If your design requires control over calling a method, then control should be exercised by testing the arguments - caller which is authorized to make a call would "know" the magic word to pass as the argument.
This is a variation of the solution suggested by #cowlinator using class AWithUnlimitedAccess derived from class A rather than class A implementing interface IA.
The result and the limitations are the same, but I like it better because (1) the limited access methods are defined inside its own class and (2) it's easier to add documentation comments.
public class A
{
public void FullAccess() { }
}
public class AWithUnlimitedAccess : A
{
public void LimitedAccess() { }
}
public class B
{
private AWithUnlimitedAccess a = new AWithUnlimitedAccess();
public A GetA()
{
return a;
}
public void Func()
{
a.FullAccess();
a.LimitedAccess();
}
}
// This represents all other classes
public class C
{
public A A;
public void Func()
{
A.FullAccess();
A.LimitedAccess(); // this will fail compile
}
}
public static class MainClass
{
static void Main(string[] args)
{
B b = new B();
b.Func();
C c = new C();
c.A = b.GetA();
c.Func();
}
}

How to define a new class that inherits from Delegate

is there anyway to do something similar to what ive got bellow.
What im trying to do is to invoke a list of delegates at a specific point in time and keep track of them, and for the sake of keeping code clean, keep the delegates to be invoked in a list of some sort.
public interface IServiceStatusDelegate
{
object DynamicInvoke(object[] args)
}
public class ServiceStatusDelegate
: Delegate, IServiceStatusDelegate
{
}
public class MyServiceStatusCheckedDelegate
: ServiceStatusDelgate
{
}
public class MyServiceStatusChangedDelegate
: ServiceStatusDelgate
{
}
public class MyClass
{
public ServiceStatusDelgate[] listOfDelegatesToInvoke;
public void InvokeRequiredDelegates()
{
foreach(ServiceStatusDelegate delegateToInvoke in this.listOfDelegatesToInvoke)
delegateToInvoke.DynamicInvoke(new object[]{this, DateTime.Now});
}
}
You don't need a list of delegates... any delegate you create in c# is going to be multicast, so all you need is any delegate, and you can combine them with +. Just invoke it and all targets will be reached. For example:
Action target = null;
...
target += Method1;
...
target += Method2;
...
if(target != null) target(); // calls Method1 and Method2
This could (although it isn't necessary for it to stand) be implemented via an event which will make the convention very obvious the caller.

Wrong Derived Class Methods Execution on Event?

public Class A
{
public A()
{
someotherclass.someevent += new EventHandler(HandleEvent);
}
private void HandleEvent(object sender,CustomEventArgs e)
{
if(e.Name == "Type1")
Method1();
else if(e.Name == "Type2")
Method2();
}
protected virtual void Method1(){}
protected virtual void Method2(){}
}
public class B: A
{
public B()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class C: A
{
public C()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class Main
{
private A;
public Main(){/*Something*/}
private void StartB()
{
A = new B();
}
private void StartC()
{
A = new C();
}
}
Now, what happens is, after I go through a cycle in which both the methods StartB(called first) and StartC(called second) are called, when the someevent is triggered, the code tries to execute the Method in Class B(and later Class C, I hope. I could not get there since it errors out when it calls method in Class B), instead which I want it to call only the method in Class C.
I think that, since the event is subscribed at constructor, Class B methods are still getting fired since it is subscribed initially on the call of StartB.
Question:
I want only the methods of the class that is instantiated the latest should be executed.
For Example: if StartB and StartC are called in order, when someevent is triggered the Methods in Class C should only get executed. Same Vice-Versa. How to do that?
I know am doing something terribly wrong. Any help is much appreciated.
You aren't unsubscribing from the event from your first instance so it will be called. If you don't want it to be called you need to unsubscribe. You could do something like this
class A
{
private static EventHandler lastHandler;
public A()
{
//warning, not thread safe
if(lastHandler != null)
{
someotherclass.someevent -= lastHandler;
}
lastHandler = new EventHandler(HandleEvent);
someotherclass.someevent += lastHandler;
}
but it seems pretty hacky. You are probably better off implementing a method (e.g. IDisposable) to clean up your last instance before a creating a new one.
If I understand you correctly you are saying the methods on B are being called after startC is called and you don't wish this to happen?
I'm guessing your issue is that someotherclass is a static class, or an instance is somehow being shared between all the created B's and C's - in which case you need to unregister the old event handler from someotherclass.someevent when you create the new class. If you don't unregister the handler then the someotherclass object will have a reference to the B or C object that registered with it, so even though you are overwriting the reference in the main class the object is still kept alive by the reference in the event and is still being called when the event is triggered.

Events returning values as methods, is it correct?

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
}
}
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.
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;
}
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();
}
}

Categories

Resources