I'm looking for a compact way to implement visitor in C#. The code is going to be used in Unity3D in "object hierarchy walker" function.
The main problem is that I don't know how to declare "universal callable argument" as a method parameter in C#.
static void visitorTest(var visitor){ // <<---- which type?
int i = 0;
visitor(i);
}
which can be easily expressed in C++ template functions
template<class Visitor> void visitorTest(Visitor visitor){
visitor(i);
}
Ideally vistior
should accept class, method (or static method) and some sort of "lambda" expression. Accepting "class" is optional.
I did try to write it in C# using information from here and here, but I did not get it right.
I'm missing some fundamental knowledge mostly related to conversion between delegates, Action, methods and Func, would be nice if someone pointed what exactly I don't know yet or just threw example at me so I can figure it out myself (fixing two compile errors would be less time consuming than explaining everything).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleTest
{
class Program
{
public delegate void Visitor(int i);
public void visitorTest(Visitor visitor){
int[] tmp = new int[10];
for (int i = 0; i < tmp.Length; i++){
tmp[i] = i;
}
foreach(var i in tmp){
visitor(i);
}
}
public static void funcCallback(int arg) {
System.Console.WriteLine("func: " + arg.ToString());
}
static void Main(string[] args)
{
//An object reference is required for the non-static field, method, or property 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)
visitorTest(new Visitor(funcCallback));
int mul = 2;
Action< int> lambda = (i) => System.Console.WriteLine("lambda: " + (2*i).ToString());
//The best overloaded method match for 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)' has some invalid arguments
//Argument 1: cannot convert from 'System.Action<int>' to 'ConsoleTest.Program.Visitor'
visitorTest(lambda);
}
}
}
C++ code example:
Ideally I would like to have equivalent of this code fragment (C++):
#include <vector>
#include <iostream>
template<class Visitor> void visitorTest(Visitor visitor){
//initialization, irrelevant:
std::vector<int> tmp(10);
int i = 0;
for(auto& val: tmp){
val =i;
i++;
}
//processing:
for(auto& val: tmp)
visitor(val);
}
//function visitor
void funcVisitor(int val){
std::cout << "func: " << val << std::endl;
}
//class visitor
class ClassVisitor{
public:
void operator()(int arg){
std::cout << "class: " << arg*val << std::endl;
}
ClassVisitor(int v)
:val{v}{
}
protected:
int val;
};
int main(){
visitorTest(funcVisitor);
visitorTest(ClassVisitor(2));
int arg = 3;
/*
* lambda visitor: equivalent to
*
* void fun(int x){
* }
*/
visitorTest([=](int x){ std::cout << "lambda: " << arg*x << std::endl;});
}
Output:
func: 0
func: 1
func: 2
func: 3
func: 4
func: 5
func: 6
func: 7
func: 8
func: 9
class: 0
class: 2
class: 4
class: 6
class: 8
class: 10
class: 12
class: 14
class: 16
class: 18
lambda: 0
lambda: 3
lambda: 6
lambda: 9
lambda: 12
lambda: 15
lambda: 18
lambda: 21
lambda: 24
lambda: 27
visitorTest
is a universal (template) function that can take lambda expression, class or a function as a callback.
funcTest
is function callback.
classTest
is a class callback.
and the last line within main() has lambda callback.
I can make class based callback easily by providing abstract base of sorts, but I'd like to have more flexible approach, because writing full blown class is often too verbose, and writing abstract base for something this simple is overkill.
Online information suggests that the way to do it is to use Linq and Delegates, but I have trouble converting between them or just passing along the delegate.
Advice?