Question

I'm tring to build a library for simplifing late binding calls in C#, and I'm getting trouble tring with reference parameteres. I have the following method to add a parameter used in a method call

    public IInvoker AddParameter(ref object value)
    {
        //List<object> _parameters = new List<object>();
        _parameters.Add(value);          

        //List<bool> _isRef = new List<bool>();
        _isRef.Add(true);

        return this;
    }

And that doesn't work with value types, because they get boxed as an object, thus they are not modified. E.g:

int param1 = 2;
object paramObj = param1;
//MulFiveRef method multiplies the integer passed as a reference parameter by 5:
//void MulFiveRef(ref int value) { value *= 5; }
fi.Method("MulFiveRef").AddParameter(ref paramObj);

That doesn't work. The late binding call is successful, and the inner List which holds the parameteres (_parameters ) does get modified, but not the value outside the call.

Does anyone knows a simple way to overcome this limitation? The AddParameter signature cannot be modified, as with late binding calls, you cannot know in advance the Type of the parameters (and either way you insert all the parameters for a call inside an object array prior to making the call)

Thanks in advance.

Was it helpful?

Solution

If the value is changing inside the method, you will need to declare a temp (object) variable to pass (ref) to the method, and unbox it yourself afterwards:

    int i = 3;
    //...
    object obj = i;
    Foo(ref obj);
    i = (int)obj;

Note that this will not allow you to update the value after the event. Something like an event or callback might be an alternative way of passing changes back to the caller.

Note also that C# 4.0 has some tricks to help with this only in the context of COM calls (where ref object is so common [plus of course dynamic for late binding, as Jon notes]).

OTHER TIPS

Your method isn't changing value anyway - why are you passing it by reference? It may make sense, but it's not really clear to me. Note that the sample code you've provided wouldn't compile anyway, as ref arguments have to be exactly the same type as the parameter.

(Also, are you aware that C# 4.0 and .NET 4.0 will have built-in support for late-binding? Chances are that the language-integrated version will be easier to use than a library-only one. Are you sure it's worth spending time on the library at this point in time?)

EDIT: The code you've provided really won't compile. You don't get boxing for ref parameters, precisely because the argument and parameter types have to be exactly the same. Here's some sample code to prove it:

public class Test
{
    static void Main()
    {
        int i;
        Foo(ref i); // Won't compile - error CS1502/1503
    }

    static void Foo(ref object x)
    {
    }
}

If your current code is compiling, then it's not the code you presented in the question. Perhaps you have another overload for AddParameter which accepts ref int?

Ok, thanks to Jon Skeet corrections and Mark Gravell code, i've come up with this interface:

        //This will be created with a factory
        IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());

        int param1 = 2;
        object paramObj = param1;

        invoker.AddParameter(ref paramObj).Invoke("MulFiveRef");

        param1 = (int)invoker.Parameters[0];

Is not exactly as I've imagined, but is way more simply and readable that my previous interface:

        IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
        int refValue = 10;
        object[] args = Args.Build(refValue);

        invoker.Call("MulFiveRef", Args.ByRefIndexs(0), args);

        refValue = (int)args[0];

Thank you very much for your help people :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top