C # delegate and abstract class

Currently, I have 2 specific methods in 2 abstract classes. One class contains the current method, while the other contains the deprecated method. For example.

// Class #1 public abstract class ClassCurrent<T> : BaseClass<T> where T : BaseNode, new() { public List<T> GetAllRootNodes(int i) { //some code } } // Class #2 public abstract class MyClassLegacy<T> : BaseClass<T> where T : BaseNode, new() { public List<T> GetAllLeafNodes(int j) { //some code } } 

I want the appropriate method to run in their relative scripts in the application. I plan to write a delegate to handle this. The idea is that I can just call the delegate and write the logic in it to process which method to call, depending on which class / project it is called from (at least this is what I consider delegates and how they are used).

However, I have some questions on this topic (after some searches):

1) Is it possible to have a delegate who knows two (or more) methods that are in different classes? 2) Is it possible to make a delegate that generates abstract classes (for example, from the above code)? (My assumption is not, because delegates create a concrete implementation of past classes) 3) I tried to write a delegate for the above code. But I am technically challenged:

  public delegate List<BaseNode> GetAllNodesDelegate(int k); GetAllNodesDelegate del = new GetAllNodesDelegate(ClassCurrent<BaseNode>.GetAllRootNodes); 

I got the following error:

 An object reference is required for the non-static field, method, property ClassCurrent<BaseNode>.GetAllRootNodes(int) 

Maybe I misunderstood something ... but if I need to manually declare a delegate in the calling class, and pass the function manually as described above, then I begin to doubt whether the delegate is a good way to handle my problem.

Thanks.

+6
c #
source share
5 answers

How you try to use delegates (constructing them with new by declaring a named type of delegation) assumes that you are using C # 1. If you really use C # 3, this is a lot easier than that.

First, your delegate type:

 public delegate List<BaseNode> GetAllNodesDelegate(int k); 

Already exists. It's simple:

 Func<int, List<BaseNode>> 

Therefore, you do not need to declare your own version.

Secondly, you should think about the fact that a delegate is like an interface with only one method, and you can "implement" it on the fly, without having to write a named class. Just write lambda or directly assign a method name.

 Func<int, List<BaseNode>> getNodesFromInt; // just assign a compatible method directly getNodesFromInt = DoSomethingWithArgAndReturnList; // or bind extra arguments to an incompatible method: getNodesFromInt = arg => MakeList(arg, "anotherArgument"); // or write the whole thing specially: getNodesFromInt = arg => { var result = new List<BaseNode>(); result.Add(new BaseNode()); return result; }; 

The lambda has the form (arguments) => { body; } (arguments) => { body; } . Arguments are separated by a comma. If there is only one, you can omit the parentheses. If it does not accept any parameters, put a couple of empty parentheses: () . If the body has only one statement, you can omit curly braces. If this is just one expression, you can omit the curly braces and the return keyword. In the body, you can refer to almost any variables and methods from the covering area (except for ref / out parameters to the placement method).

You almost never need to use new to instantiate a delegate. And it is rarely required to declare custom delegate types. Use Func for delegates that return a value and Action for delegates that return a void .

Whenever the thing you need to pass looks like an object with one method (be it an interface or a class), then use a delegate instead, and you can avoid a big mess.

In particular, avoid defining interfaces in one way. It just means that instead of writing lambda to implement this method, you will have to declare a separate named class for each other implementation with a template:

 class Impl : IOneMethod { // a bunch of fields public Impl(a bunch of parameters) { // assign all the parameters to their fields } public void TheOneMethod() { // make use of the fields } } 

The lambda effectively does all this for you, eliminating such mechanical patterns from your code. You just say:

 () => /* same code as in TheOneMethod */ 

This also has the advantage that you can update variables in the scope because you can access them directly (instead of working with values ​​copied to the fields of the class). This can sometimes be a disadvantage if you do not want to change the values.

+7
source share

You may have a delegate that is initialized with references to various methods depending on certain conditions.

Regarding your questions:
1) I'm not sure what you mean by "knows." You can pass a method to a delegate, so if you can write a method that "knows" about some other methods, than you can do a similar delegate.
2) Again, delegates can be created from any method that can be executed. For example, if you have an initialized local variable of type ClassCurrent<T> , you can create a delegate for any instance method of type ClassCurrent<T> .
3) A delegate can only call a method that can actually be called. I mean, you cannot call ClassCurrent.GetAllRootNodes because GetAllRootNodes not a static method, so you need an instance of ClassCurrent to call it.

A delegate can remain in any class that has access to ClassCurrent and MyClassLegacy .

For example, you can create smth as:

 class SomeActionAccessor<T> { // Declare delegate and fied of delegate type. public delegate T GetAllNodesDelegate(int i); private GetAllNodesDelegate getAllNodesDlg; // Initilaize delegate field somehow, eg in constructor. public SomeActionAccessor(GetAllNodesDelegate getAllNodesDlg) { this.getAllNodesDlg = getAllNodesDlg; } // Implement the method that calls the delegate. public T GetAllNodes(int i) { return this.getAllNodesDlg(i); } } 

Delegates can carry both static and instance methods. The only difference is that to create a delegate with an instance method, you need an instance of the class to which this method belongs.

+1
source share

Let both ClassCurrent and MyClassLegacy implement the INodeFetcher interface:

 public interface INodeFetcher<T> { List<T> GetNodes(int k); } 

For ClassCurrent call the GetAllRootNodes method from the interface implementation and for MyLegacyClass method.

+1
source share

Why do you need a delegate? That sounds too complicated. I would just create a method in a new class that you could set when you needed to call you. Some contextual information may be provided to this class to help it solve. Then I would implement the logic in a new method, which would decide whether to call the current method or the inherited method.

Something like that:

 public class CurrentOrLegacySelector<T> { public CurrentOrLegacySelector(some type that describe context) { // .. do something with the context. // The context could be a boolean or something more fancy. } public List<T> GetNodes(int argument) { // Return the result of either current or // legacy method based on context information } } 

This will give you a clean wrapper for methods that are easy to read and understand.

0
source share

As a variation on the theme suggested by Runa Grimstad, I think you could use a strategy template (e.g.
An introduction to the GOF strategy template in C # ).

This would be especially interesting if you cannot modify the LegacyClass (and therefore it may not be easy to use the “interface approach” proposed by Cornelius), and if you use dependency injection (DI; Injection injection ). DI (possibly) will allow you to enter the correct implementation (specific strategy) in the right place.

Strategy:

 public interface INodeFetcher<T> { List<T> GetNodes(int k); } 

Specific Strategies:

 public class CurrentSelector<T> : INodeFetcher<T> { public List<T> GetNodes(int argument) { // Return the result "current" method } } public class LegacySelector<T> : INodeFetcher<T> { public List<T> GetNodes(int argument) { // Return the result "legacy" method } } 

-> Enter / create the correct specific strategy.

Hi

0
source share

All Articles