jeudi 7 septembre 2023

Invoke a method using reflection

I am trying to connect to and subscribe to Topics on ROSbridge using the ros-sharp project. It works fine if i specify the Type of message upon subscribing as per the code example in the Test Client:

rosSocket = new RosSocket(new RosBridgeClient.Protocols.WebSocketNetProtocol(uri), RosSocket.SerializerEnum.Newtonsoft_JSON);
string subscription_id = rosSocket.Subscribe<JointState>("/joint_states", SubscriptionHandler);

Where this is the Subscribe method:

public string Subscribe<T>(string topic, SubscriptionHandler<T> subscriptionHandler, int throttle_rate = 0, int queue_length = 1, int fragment_size = int.MaxValue, string compression = "none") where T : Message
{
string id;
lock (SubscriberLock)
{
id = GetUnusedCounterID(Subscribers, topic);
Subscription subscription;
Subscribers.Add(id, new Subscriber<T>(id, topic, subscriptionHandler, out subscription, throttle_rate, queue_length, fragment_size, compression));
Send(subscription);
}
return id;
}

And the Subscription Handler is as follows:

private static void SubscriptionHandler(object message)
{
    string msg = JsonConvert.SerializeObject((Message)message, Formatting.None);
    Console.WriteLine(msg);
}

however I wish to be able to specify the topic and message type by string and find that type and call the subscribe method.

I know I can do it with an exhaustive Switch e.g.:

public static string SubscribeSwitch(string type, string topic) 
{
switch (type)
{
case "sensor_msgs/JointState":
    return rosSocket.Subscribe<JointState>(topic, SubscriptionHandler);
    break;
case "actionlib_msgs/GoalID":
    return rosSocket.Subscribe<GoalID>(topic, SubscriptionHandler);
    break;
}
return "";
}

But this will get pretty long and unmanageable especially if i add new Message types for different robots. I have therefore spent some time trying to use reflection to get the type to invoke the Subscribe call, but I seem to be falling over when trying to pass in the Subscription handler which has a non generic delegate type. Has anyone done similar, or provide an example of how to do this - many thanks. The following code for exmaple falls over at var subscribe: InvalidCastException: Unable to cast object of type 'System.RuntimeType' to type 'RosSharp.RosBridgeClient.Message'.

Type msgType = Type.GetType("RosSharp.RosBridgeClient.MessageTypes.Sensor.JointState,RosBridgeClient");

var mi = typeof(RosSocket).GetMethod("Subscribe");

Type[] aparams = new Type[1];
aparams[0] = msgType;
var fooRef = mi.MakeGenericMethod(aparams);

object[] test2 = new object[1];
test2[0] = msgType;

object[] test = new object[6];
test[0] = "/joint_states";

// get subscribe method info
var subscribe = typeof(RosSocketConsole).GetMethod(nameof(SubscriptionHandler), BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, test2);

test[1] = subscribe;
test[2] = 0;
test[3] = 1;
test[4] = int.MaxValue;
test[5] = "none";
string subscription_id = (string)fooRef.Invoke(rosSocket, test);

Thanks for any assistance





Aucun commentaire:

Enregistrer un commentaire