I am trying to port an SDK written in java to C#.
In this software there are many "handler" interfaces with several methods (for example: attemptSomethingHandler
with success()
and several different failure methods). This interface is then implemented and instantiated anonymously within the calling class and passed to the attemptSomething
method of the SomethingModel
class. This is an async method and has several places where it could fail or calls another method (passing on the handler). This way, the anonymous implementation of attemptSomethingHandler
can reference private methods in the class that calls attemptSomething
.
In C# it is not possible to anonymously implement an interface. I could explicitly implement a new class, but this implementation would be unique to this calling class and not used for anything else. More importantly, I would not be able to access the private methods in the calling class, which I need and do not want to make public.
Basically, I need to run different code from the calling class depending on what happens in the SomethingModel
class methods.
I've been reading up on delegates but this would require passing as many delegates as there are methods in the handler interface (as far as I can tell). What is the appropriate way to do this in C#? I feel like I'm missing out on a very common programming strategy. There simply must be an easy, clean way to structure and solve this problem.
Using delegates:
void AttemptSomethingAsync(Action onSuccess, Action<string> onError1, Action onError2 = null) {
// ...
}
// Call it using:
AttemptSomethingAsync(onSuccess: () => { Yes(); }, onError1: (msg) => { OhNo(msg); });
Or, using a class
class AttemptSomethingHandler {
Action OnSuccess;
Action<string> OnError1;
Action OnError2;
}
void AttemptSomethingAsync(AttemptSomethingHandler handler) {
// ...
}
// And you call it like
AttemptSomethingAsync(new AttemptSomethingHandler() {
OnSuccess = () => { Yes() };
});
Or events
public delegate void SuccessHandler();
public delegate void ErrorHandler(string msg);
class SomethingModel {
public event SuccessHandler OnSuccess;
public event ErrorHandler OnError1;
public void AttemptSomethingAsync() {
// ...
}
}
// Use it like
var model = new SomethingModel();
model.OnSuccess += Yes;
model.AttemptSomethingAsync();
private void Yes() {
}
In C#, we don't have anonymous types like Java per se. You can create an anonymous type which contains fields like so:
var myObject = new { Foo = "foo", Bar = 1, Quz = 4.2f }
However these cannot have methods placed in them and are only passable into methods by use of object
or dynamic
(as they have no type at compile-time, they are generated by the compiler AFAIK)
Instead in C# we use, as you said, delegates or lambdas.
If I understand your pickle correctly, you could implement a nested private class like so:
interface IMyInterface
{
void Foo();
}
class MyClass
{
public void Bar()
{
var obj = new MyInterface();
obj.Foo();
}
private class MyInterface : IMyInterface
{
public void Foo()
{
// stuff
}
}
}
Now MyClass
can create an instance of MyInterface
which implements IMyInterface
. As commentors have mentioned, MyInterface
can access members of MyClass
(although you most certainly want to try and stick to using publicly accessible members of both types).
This encapsulates the "anonymous" class (using Java terms here to make it simpler) and also means that you could potentially return MyInterface
as an IMyInterface
and the rest of the software would be none the wiser. This is actually how some abstract factory patterns work.
Basically, I need to run different code from the calling class depending on what happens in the SomethingModel class methods.
This smells of heavy coupling. Oh dear!
It sounds to me like your particular problem could use refactoring. In C# you can use Events to solve this (note: Can, not should). Just have an Event for each "branch" point of your method. However I must say that this does make your solution harder to envisage and maintain.
However I suggest you architect your solution in a way such that you don't need such heavy coupling like that.
You could also try using a Pipeline model but I'm not sure how to implement that myself. I know that jetty (or is it Netty? the NIO for Java by JBOSS) certainly used a similar model.
You may find that throwing out some unit tests in order to test the expected functionality of your class will make it easier to architect your solution (TDD).
You can use nested classes to simulate anonymous classes, but in order to use nested classes in the same way as Java you will need to pass a reference to the outer class. In Java all nested and anonymous classes have this by default, and only static ones do not.
interface IMyInterface
{
void Foo();
}
class MyClass
{
public void Bar()
{
IMyInterface obj = new AnonymousAnalog(this);
obj.Foo();
}
private class AnonymousAnalog : IMyInterface
{
public void Foo(MyClass outerThis)
{
outerThis.privateFieldOnOuter;
outerThis.PrivateMethodOnOuter();
}
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With