2

Project

I've developed a remoting class which is used to replace a subset of WCF. This has been done because we are targeting a mobile Plattform with Unity3D and need to keep the Memory consumption as small as possible. ( So we don't need to include System.ServiceModel which actually has a size of 2.7MB which is a lot for a small mobile RAM )

It's working fine right now for all types ( including complex types which will be serialized using my own serializer written years ago ) and it's also capable to handle complex situations ( A calls B, B calls A, A returns something, B returns something ).

Method invokation

For invoking methods on the target site i'm using Type.InvokeMember which actually works for the most cases except for nullable-types. And this is the problem i've faced. In my interface definition the method looks like this:

public interface IServerContract 
{
    void SetUsageID(Int32? id);
}

The ServerProxy ( A object which handles the call to the remote method ) i'm doing the following:

public class ServerProxy : ProxyBase
{
    public void SetUsageID(Int32? id)
    {
         RemoteCall("SetUsageID", id);
    }
}

As usual the parameter id is boxed because the definition of RemoteCall looks like this:

public void RemoteCall(String methodName, params Object[] arguments) { ... }

At this point i got only a System.Int32 and not a nullable anymore. I'm serializing the arguments and deserializing them on the target machine. At this point i'm calling Type.InvokeMethod which causes a exception because he can't find a method which takes a Int32 as first parameter ( second when not ignoring this ).

What is the best solution for this issue? There are serval ways but all would cause a performance impact.

Community
  • 1
  • 1
Felix K.
  • 6,201
  • 2
  • 38
  • 71

1 Answers1

2

The boxing rules for int? indeed mean that once you have it as an object you see:

  • empty values are null, and nothing more can be discerned
  • non-empty values are known only as the non-nullable type
    • so specifically, passing (int)5 and (int?)5 have exactly the same appearance within object

As such, the options available:

  • ensure method names are unique, so you can uniquely resolve by name to a MethodInfo, then use MethodInfo.Invoke (this ensures no ambiguity in the parameters)
  • try to resolve a method accepting the non-nullable type(s), then look for nullable type(s) instead (gets complex for multi-parameter methods)
  • pass more metadata about what method you are calling (increases size)

Personally, though, I have a very simplistic view on such things... rather than trying to encode a vague multi-parameter method, another option is to simplify to always passing a single, DTO-based, parameter - i.e. instead of SetUsageID(int?) you could have SetUsage(SetUsageArgs) (or something similar), where SetUsageArgs happens to have a single property. The point being: you're now just encoding a single DTO, and once you have deserialized that DTO there is no ambiguity.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thank you for your help, i'm creating unique id's for each of the methods when the connection is established and save them in a table, then i just have to send a 7bit encoded int over the network to find the correct method. – Felix K. May 08 '12 at 15:28