2

I'm making a networking application where I want to implement strongly typed RPC. As result I'd like to be able to pass methods no matter the parameters so I can get them and store them in a dictionary so I can construct request parameters properly as well once a packet arrive I am able to read it using the parameters the same remote method used

I'd like something like this:

Register(Enum key, [method with unknown parameters])
4
  • The prasing of the first paragraph is very confusing (at least to me). Can you please add a few more sentences to describe what you're trying to do? Is the "networking application" part relevant? Commented Apr 28, 2020 at 17:57
  • Not really its more to tell from where i am comming from with this, essentially i just want a method that gets the parameter types of any method you pass it kind of something like this MyMethod(Action action) but where Action can have any kind and number of parameters Commented Apr 28, 2020 at 18:02
  • Perhaps show the code that isn't working so we can help with the specific problem Commented Apr 28, 2020 at 18:19
  • Do you deliberately want to roll your own breed or would just using something like gRPC be good for you? Commented Apr 28, 2020 at 18:46

3 Answers 3

2

In C# 8.0 using generics and Delegate Constraint you can do something like this:

using System;
using System.Collections.Generic;

namespace ConsoleApp
{

    public class Program
    {
        public static void Main(params string[] args)
        {
            var app = new NetworkingApplication();
            app.Register<Action<int, string>>(PacketType.Type1, Method1, 1, "string1 argument");
            app.Register<Func<string, string>>(PacketType.Type2, Method2, "string2 argument");
            app.OnPacketReceived(PacketType.Type1);
            app.OnPacketReceived(PacketType.Type2);
        }

        public static void Method1(int arg1, string arg2)
        {
            Console.WriteLine($"Method1 Invoked with args: {arg1}, {arg2}");
        }

        public static string Method2(string arg1)
        {
            Console.WriteLine($"Method2 Invoked with args: {arg1}");
            return "Foo";
        }
    }

    public class NetworkingApplication
    {
        private readonly IDictionary<PacketType, DelegateInvoker> _registrations;

        public NetworkingApplication()
        {
            _registrations = new Dictionary<PacketType, DelegateInvoker>();
        }

        public void Register<TDelegate>(PacketType packetType, TDelegate @delegate, params object[] args)
            where TDelegate : Delegate
        {
            _registrations[packetType] = new DelegateInvoker(@delegate, args);
        }

        //invoke this when the packet is received
        public void OnPacketReceived(PacketType type)
        {
            if (_registrations.TryGetValue(type, out var invoker))
            {
                invoker.Invoke();
            }
        }

        private class DelegateInvoker
        {
            public DelegateInvoker(Delegate @delegate, object[] args)
            {
                Delegate = @delegate;
                Arguments = args;
            }

            private Delegate Delegate { get; }
            private object[] Arguments { get; }

            public void Invoke()
            {
                Delegate.Method.Invoke(Delegate.Target, Arguments);
            }
        }
    }





    public enum PacketType
    {
        Type1,
        Type2,
        Type3
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

As mentioned above you can use MethodInfo, it belongs to the System.Reflection namespace. To do this, first get the Type type of the object like this:

var type = obj.GetType()

After this you can use var methods = type.GetMethods(). This will give you an MethodInfo[]. Search the element, using your favorite method for doing so. Such as Linq:

var method = methods.Where(it => it.Name == __yourName__).LastOrDefault();

*where yourName is the name of your method.

Now you have the method you are looking for. Get the parameters using

var parameters = method.getParameters();

And there are the parameters as ParameterInfo[]. From there you can get the type of each parameter using the parameter.ParameterType property.

This being said be very careful with Reflection, it is very, very powerful but can decrease performance heavily, when overused.

Have look at it System.Reflection namespace here .

You can now add the method to a collection, such as a dictionary:

var dictionary = new Dictionary<int,MethodInfo>();
dictionary.Add(1, method);

And retrieve it like this:

var method = dictionary[1];

To call the function you can user method.Invoke() and pass in the parameters as need.

EDIT: If you would like to send the parameters as well as the function over a network. You could create a new class that serves as a DTO Data Transfer Object. This class could have as property an Array of parameters (ParameterInfo[]), the MethodInfo and anything else you want.

You could then serialize the object (maybe json) and send it to another system, that could then deserialize it, and Invoke the MethodInfo obj

2 Comments

I understand now, i pass to my method a string "MethodName" and it will use reflection to look for all methods in "this", good thing that you mention performance because i'll need to run this like 100 times at start, i'm not sure how much that translate in time but i don't know if i'd rather wait 1-5 minutes than write my packets struct by hand... sad that C# doesn't have i "function" type
I would say, if it is only while initializing it is okay. Also, for most apps you will be ok using it here and there. It's just very bad if you have an UI that needs to stay responsive or other clients that may need to be served from your service. I consider reflection kind of a last restort thing. Somethings just can't be done any otherway, such as "analyzing" the source code.
0
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{

    public class Program
    {
        public static void Main(params string[] args)
        {
            var app = new NetworkingApplication();
            app.Register(PacketType.Type1, () =>
            {
                Console.WriteLine("Type1 Packet is received!");
            });
        }
    }

    public class NetworkingApplication
    {
        private readonly IDictionary<PacketType, Action> _registrations;

        public NetworkingApplication()
        {
            _registrations = new Dictionary<PacketType, Action>();
        }

        public void Register(PacketType packetType, Action method)
        {
            _registrations[packetType] = method;
        }

        //invoke this when the packet is received
        public void OnPacketReceived(PacketType type)
        {
            if (_registrations.TryGetValue(type, out var action))
            {
                action?.Invoke();
            }
        }
    }



    public enum PacketType
    {
        Type1,Type2,Type3
    }
}

3 Comments

Yes this is kind of what i have currently but I need to be able to pass any kind of method (parameter wise) instead of Action
You can wrap any method you like inside the action
How would you go about having an action with parameters? You can capture them, ok. But OP is talking about RPC. How would you transfer the parameters across process and even machine borders?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.