conditional logic based on type - c#

Given:
interface I
{
}
class B: I
{
}
class C: I
{
}
class A
{
public void Method(B arg)
{
}
public void Method(C arg)
{
}
public void Method(I arg)
{
// THIS is the method I want to simplify.
if (I is B)
{
this.Method(arg as B);
}
else if (I is C)
{
this.Method(arg as C);
}
}
}
I know that there are better ways to design this type of interactions, but because of
details which would take too long to explain this is not possible.
Since this pattern will be duplicated MANY times, I would like to replace the
conditional logic with a generic implementation which I could use just one line.
I can't see a simple way to implement this generic method/class, but my instincts tell me it should be possible.
Any help would be appreciated.

I would put the method inside the interface and then let polymorphism decide which method to call
interface I
{
void Method();
}
class B : I
{
public void Method() { /* previously A.Method(B) */}
}
class C : I
{
public void Method() { /* previously A.Method(C) */ }
}
class A
{
public void Method(I obj)
{
obj.Method();
}
}
Now when you need to add a new class, you only need to implement I.Method. You don't need to touch A.Method.

What you want is double dispatch, and visitor pattern in particular.

This is kinda ugly but it gets the job done:
public void Method(B arg)
{
if (arg == null) return;
...
}
public void Method(C arg)
{
if (arg == null) return;
...
}
public void Method(I arg)
{
this.Method(arg as B);
this.Method(arg as C);
}
I don't think I would do it this way, though. It actually hurts looking at that. I'm sorry I forced you all to look at this as well.

interface I
{
}
class B : I
{
}
class C : I
{
}
class A
{
public void Method(B arg)
{
Console.WriteLine("I'm in B");
}
public void Method(C arg)
{
Console.WriteLine("I'm in C");
}
public void Method(I arg)
{
Type type = arg.GetType();
MethodInfo method = typeof(A).GetMethod("Method", new Type[] { type });
method.Invoke(this, new I[] { arg });
}
}

It doesn't exist in a convenient form withing C# - see here for an idea based on F#'s pattern matching, that does exactly what you want. You can do some things with reflection to select the overload at runtime, but that will be very slow, and has severe issues if anything satisfies both overloads. If you had a return value you could use the conditional operator;
return (I is B) ? Method((B)I) : ((I is C) ? Method((C)I) : 0);
Again - not pretty.

Easy. In Visual Basic I do this all the time using CallByName.
Sub MethodBase(value as Object)
CallByName(Me, "RealMethod", CallType.Method, value)
This will call the overload of RealMethod that most closely matches the runtime type of value.
I'm sure you can use CallByName from C# by importing Microsoft.VisualBasic.Interaction or by creating your own version using reflection.

Related

How to create template with a set of sealed class

I have several sealed class from a code I can't rewrite. (therefore I can't not make those class implement a same interface).
I have several function that make the same thing for this class:
void fN(int i, sealedClassN sc)
{
list.Add(new delegateCreator(sc));
button.Click += list.[i]._delegate;
}
(and of course delegateCreator( sealedClassN ) is implemented (but without using template because what it does is very different each time))
I would like to create that:
void f<sealedClass >(int i, sealedClass sc) with sealedClass : sealedClass1or or sealedClass2 or sealedClass3 ....
{
list.Add(new delegateCreator(sc));
button.Click += list.[i]._delegate;
}
Is there a way to do that.
Thank you for your help
Unfortunately, this is not directly possible. I can suggest the following alternatives:
Option 1: Pass a delegateCreator instead:
// call as fN(i, new delegateCreator(sc))
//
void fN(int i, delegateCreator dc)
{
list.Add(dc);
button.Click += list.[i]._delegate;
}
Option 2: If you have a more complicated function which only conditionally creates a delegateCreator, you can pass a lambda expression as the parameter:
// call as fN(i, () => new delegateCreator(sc))
//
void fN(int i, Func<delegateCreator> dcfunc)
{
if (someCondition)
{
list.Add(dcfunc.Invoke());
button.Click += list.[i]._delegate;
}
}
I don't think you can do that. The problem with your T : T1 or T2 ... idea is that you don't have a shared member set for your argument.
Consider this
public class Type1
{
public void M()
{
}
}
public class Type2
{
public void M()
{
}
}
public static class Extension
{
public static void A<T>(T obj) where T : Type1 or Type2
{
obj.M();
}
}
Both classes have a methode M() but for the compiler it isn't the same, because they don't have a shared type that declares this methode.

Why is my interface method call ignored in a C# generic?

I am quite new to C# and I cannot understand the behaviour of a class in my project.
I am using an interface that defines a generic with a type constraint which is another interface.
When I call the generic, I know that a certain method exists on the argument (because of the type constraint), but this method doesn't get executed when I call it.
The only workaround I have so far is to include the method call into the type-specific method overloads.
This may be better explained with the following snippet with an equivalent type structure:
public interface ITrickable
{
void GetRabbitOut();
}
public interface IMagic
{
void DoTricks<T>(T obj) where T : ITrickable;
}
public class Hat : ITrickable
{
public void LiftUp() { Console.WriteLine("Lifting up the hat..."); }
public void GetRabbitOut() { Console.WriteLine("A rabbit came out the hat !"); }
}
public class Box : ITrickable
{
public void OpenDoubleBottom() { Console.WriteLine("Opening the box..."); }
public void GetRabbitOut() { Console.WriteLine("A rabbit came out the box !"); }
}
public abstract class Magician : IMagic
{
public abstract void DoTricks<T>(T obj) where T : ITrickable;
}
Now if I call DoTricks(new Hat()); DoTricks(new Box()); with the class below:
public class Houdini : Magician
{
public override void DoTricks<T>(T obj)
{
try {
DoTricks(obj); }
catch {
throw new NotImplementedException(); }
}
public void DoTricks(Hat obj)
{
obj.LiftUp();
obj.GetRabbitOut();
}
public void DoTricks(Box obj)
{
obj.OpenDoubleBottom();
obj.GetRabbitOut();
}
}
The output is as expected:
Lifting up the hat...
A rabbit came out the hat !
Opening the box...
A rabbit came out the box !
But if the class is defined as this one below:
public class Genesta : Magician
{
public override void DoTricks<T>(T obj)
{
try {
DoTricks(obj);
obj.GetRabbitOut(); } // <--- This seems to be ignored !?
catch {
throw new NotImplementedException(); }
}
public void DoTricks(Hat obj)
{
obj.LiftUp();
}
public void DoTricks(Box obj)
{
obj.OpenDoubleBottom();
}
}
The output is
Lifting up the hat...
Opening the box...
The question is why does GetRabbitOut is not called in the second class?
EDIT: The calling code is:
public static void Main(string[] args)
{
var houdini = new Houdini();
var hat = new Hat();
var box = new Box();
houdini.DoTricks(hat);
houdini.DoTricks(box);
Console.ReadLine();
}
Notice your method calls (I imagine it looked something resembling this):
Genesta g = new Genesta();
g.DoTricks(new Hat());
g.DoTricks(new Box());
Since you call g.DoTricks(new Hat()) rather than g.DoTricks<Hat>(new Hat()), no surprises that the exact method of the Genesta class that is invoked is DoTricks(T obj) and not DoTricks<T>(T obj). And when considering the implementation of DoTricks(T obj)...
public void DoTricks(Hat obj)
{
obj.LiftUp();
}
public void DoTricks(Box obj)
{
obj.OpenDoubleBottom();
}
The result is actually what you can expect from these methods!
If, however, you would call the generic method like this...
g.DoTricks<Hat>(new Hat());
You would fall into an infinite recursion, as the method would call itself indefinitely. DoTricks<T>(T obj) will always call itself and not one of the specialized overloads DoTricks(Hat) or DoTricks(Box), since the compiler cannot know before runtime that T will in fact be either Hat or Box.
By the way, the Houdini class experiences the same effect - it just so happens that its specific DoTricks(Hat) and DoTricks(Box) methods produce the result that you expected from calling DoTricks<T>(T obj).

C# Interface reference and this [duplicate]

If I have
public class AImplementation:IAInterface
{
void IAInterface.AInterfaceMethod()
{
}
void AnotherMethod()
{
((IAInterface)this).AInterfaceMethod();
}
}
How to call AInterfaceMethod() from AnotherMethod() without explicit casting?
There are lots of ways of doing this without using the cast operator.
Technique #1: Use "as" operator instead of cast operator.
void AnotherMethod()
{
(this as IAInterface).AInterfaceMethod(); // no cast here
}
Technique #2: use an implicit conversion via a local variable.
void AnotherMethod()
{
IAInterface ia = this;
ia.AInterfaceMethod(); // no cast here either
}
Technique #3: write an extension method:
static class Extensions
{
public static void DoIt(this IAInterface ia)
{
ia.AInterfaceMethod(); // no cast here!
}
}
...
void AnotherMethod()
{
this.DoIt(); // no cast here either!
}
Technique #4: Introduce a helper:
private IAInterface AsIA => this;
void AnotherMethod()
{
this.AsIA.IAInterfaceMethod(); // no casts here!
}
You can introduce a helper private property:
private IAInterface IAInterface => this;
void IAInterface.AInterfaceMethod()
{
}
void AnotherMethod()
{
IAInterface.AInterfaceMethod();
}
Tried this and it works...
public class AImplementation : IAInterface
{
IAInterface IAInterface;
public AImplementation() {
IAInterface = (IAInterface)this;
}
void IAInterface.AInterfaceMethod()
{
}
void AnotherMethod()
{
IAInterface.AInterfaceMethod();
}
}
And yet another way (which is a spin off of Eric's Technique #2 and also should give a compile time error if the interface is not implemented)
IAInterface AsIAInterface
{
get { return this; }
}
You can't, but if you have to do it a lot you could define a convenience helper:
private IAInterface that { get { return (IAInterface)this; } }
Whenever you want to call an interface method that was implemented explicitly you can use that.method() instead of ((IAInterface)this).method().
Yet another way (not best):
(this ?? default(IAInterface)).AInterfaceMethod();
Can't you just remove the "IAInterface." from the method signature?
public class AImplementation : IAInterface
{
public void AInterfaceMethod()
{
}
void AnotherMethod()
{
this.AInterfaceMethod();
}
}

Advise on abstraction

I am working on some code whereby I have an abstract class that has a few core properties and a Run(int index) method. I then create new types that inherit this. These new types can have multiple methods that can be called according to the index passed in.
public abstract class BaseClass
{
public abstract void Run(int index);
}
public class Class1 : BaseClass
{
public override void Run(int index)
{
if (index == 0)
{
MethodA();
}
else if (index == 1)
{
MethodB();
}
}
private void MethodA()
{
//do stuff
}
private void MethodB()
{
//do stuff
}
}
I'm just wondering is there a better way to do this. These types and methods would be called from a UI, - a menu click for example. So I might have a class1 and a class2. Class1 might have 3 methods so I could call run(0) ... run(2) on it. Class2 might just have one internal method so I would just call run(0). Maybe I would need to keep a collection of ints with each class I guess as a map to methods. Might also have to add a string to this collection to hold a friendly name for menu items etc..
Can you think of a way to implement this type of mapping while maintaining as much abstraction as possible? Is there a better way to go about this that my current idea?
One way:
You could use an interface instead:
public interface IRunnableSomething {
void Run();
}
public class MyRunnableA :IRunnableSomething
{
public void Run() {
// do stuff
}
}
public class MyRunnableB :IRunnableSomething
{
public void Run() {
// do stuff
}
}
Then in your main class...
public override void Run(IRunnable runnable)
{
runnable.Run();
}
Example of calling it:
myInstanceOfMainClass.Run(new MyRunnableA());
This seems fitting, since you already know what index you were passing in with your original version. This just moves it from int based to interface based (less code too in the end).
Let me explain a bit further so. Here's a slightly more verbose version of what I am trying to do. You can see here that my abstract class has the list of indexes for pointing at the right method in derived classes, and you can see where I am loading types and creating menu items in a UI. I am using this ItemPointer list and passing around ItemPointers to tag properties etc. It all feels a bit wrong somehow.
I wish for the whole thing to be extensible. I might want to add a Class2, Class3 etc all inheriting BaseClass. I might also want to create plugins using BaseClass. Any derived class will have at least one but runable method but will likely have many. So Class1 here is just an example. Does this help explain myself? please go easy on me, I'm learning and that's why I am asking here.
Is what I'm doing here awful? or is it ok? or is there a better way? I guess that's my question. If there is a better way, I'd really appreciate an example. Many thanks to all for the help. It is much appreciated.
public abstract class BaseClass
{
public List<ItemPointer> ItemPointers = new List<ItemPointer>();
public abstract void Run(int index);
}
public class ItemPointer
{
public int Index { get; set; }
public string ClassType { get; set; }
public string UIDescription { get; set; }
}
public class Class1 : BaseClass
{
public Class1()
{
ItemPointers.Add(new ItemPointer { Index = 0, ClassType = this.GetType().Name, UIDescription = "MethodA Description" });
ItemPointers.Add(new ItemPointer { Index = 1, ClassType = this.GetType().Name, UIDescription = "MethodB Description" });
}
public override void Run(int index)
{
if (index == 0)
{
MethodA();
}
else if (index == 1)
{
MethodB();
}
}
private void MethodA()
{
//do stuff
}
private void MethodB()
{
//do stuff
}
}
public class UIForm
{
private List<BaseClass> _baseClasses;
//Formload events load all baseclass types (including plugins via reflection during form init etc. Then call loadUIitems
private void LoadUIItems()
{
foreach (BaseClass bc in _baseClasses)
{
foreach (var p in bc.ItemPointers)
{
ToolStripMenuItem t = new ToolStripMenuItem(p.UIDescription);
t.Click += new EventHandler(WorkerMenu_Click);
t.Tag = p;
actionsToolStripMenuItem.DropDownItems.Add(t);
}
}
}
void WorkerMenu_Click(object sender, EventArgs e)
{
ToolStripMenuItem t = (ToolStripMenuItem)sender;
ItemPointer p = (ItemPointer)t.Tag;
foreach (BaseClass bc in _baseClasses)
{
if (bc.GetType().Name == p.ClassType)
{
bc.Run(p.Index);
}
}
}
}
In your position I might be inclined to try do something like this:
void Main()
{
var a = new Class1();
var b = new Class2();
try
{
a.Run("Foo");
b.Run("Bar", "Yoda");
b.Run("Bat"); // throws exception
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
}
}
class Base
{
public void Run(string commandName, params object[] args)
{
var method = this.GetType().GetMethod(commandName);
if(method != null)
method.Invoke(this, args);
else
throw new Exception("the command " + commandName + " does not exist on " + this.GetType().Name);
}
}
class Class1 : Base
{
public void Foo()
{
Console.WriteLine ("I am foo");
}
}
class Class2 : Base
{
public void Bar(string str)
{
Console.WriteLine ("I am {0}", str);
}
}
Output:
I am foo
I am Yoda
the command Bat does not exist on Class2

implementing delegates in c#

This would be the first time I'd use delegates in c# so please bear with me. I've read a lot about them but never thought of how/why to use this construct until now.
I have some code that looks like this:
public class DoWork()
{
public MethodWorkA(List<long> TheList) {}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
I call MethodWorkA from a method outside the class and MethodWorkA calls MethodWork 1 and 2. When I call methodA, I'd like to pass some sort of parameter so that sometimes it just does MethodWork1 and sometimes it does both MethodWork1 and MethodWork2.
So when I call the call it looks like this:
DoWork MyClass = new DoWork();
MyClass.MethodA...
Where does the delegate syntax fit in this?
Thanks.
public void MethodWorkA(Action<ParamType1, ParamType2> method) {
method(...);
}
You can call it using method group conversion:
MethodWorkA(someInstance.Method1);
You can also create a multicast delegate that calls two methods:
MethodWorkA(someInstance.Method1 + someInstance.Method2);
For what you described, you don't need delegates.
Just do something like this:
public class DoWork
{
public void MethodWorkA(List<long> theList, bool both)
{
if (both)
{
MethodWork1(1);
MethodWork2(1);
}
else MethodWork1(1);
}
public void MethodWork1(int parameters) { }
public void MethodWork2(int parameters) { }
}
If you're just experimenting with delegates, here goes:
public partial class Form1 : Form
{
Func<string, string> doThis;
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
}
void Form1_Shown(object sender, EventArgs e)
{
doThis = do1;
Text = doThis("a");
doThis = do2;
Text = doThis("a");
}
string do1(string s)
{
MessageBox.Show(s);
return "1";
}
string do2(string s)
{
MessageBox.Show(s);
return "2";
}
}
Considering that all methods are inside the same class, and you call MethodWorkA function using an instance of the class, I honestly, don't see any reason in using Action<T> or delegate, as is I understood your question.
When I call methodA, I'd like to pass some sort of parameter so that
sometimes it just does MethodWork1 and sometimes it does both
MethodWork1 and MethodWork2.
Why do not just pass a simple parameter to MethodWorkA, like
public class DoWork()
{
public enum ExecutionSequence {CallMethod1, CallMethod2, CallBoth};
public MethodWorkA(List<long> TheList, ExecutionSequence exec)
{
if(exec == ExecutionSequence.CallMethod1)
MethodWork1(..);
else if(exec == ExecutionSequence.CallMethod2)
MethodWork2(..);
else if(exec == ExecutionSequence.Both)
{
MethodWork1(..);
MethodWork2(..);
}
}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
Much simplier and understandable for your class consumer.
If this is not what you want, please explain.
EDIT
Just to give you an idea what you can do:
Example:
public class Executor {
public void MainMethod(long parameter, IEnumerable<Action> functionsToCall) {
foreach(Action action in functionsToCall) {
action();
}
}
}
and in the code
void Main()
{
Executor exec = new Executor();
exec.MainMethod(10, new List<Action>{()=>{Console.WriteLine("Method1");},
()=>{Console.WriteLine("Method2");}
});
}
The output will be
Method1
Method2
In this way you, for example, can push into the collection only functions you want to execute. Sure, in this case, the decision logic (which functions have to be executed) is determined outside of the call.

Categories

Resources