3

I need to store the Parameter<T1> returned by Build() as a Parameter<object> (because I'm storing the parameters in an array, the other way is just wayyyy too much copy-pasting the same class for each amount of parameters, since c# doesn't have variadic generics).

The problem is the cast (Parameter<object>) (object) (/* value of type Parameter<int> */);, since int isn't castable to object. How do I solve this issue?

I have the following monstrosity (imagine T1 is int):

    public static IEventBuilder<(IOrigin origin, T1 arg1, T2 arg2)>
        Params<T1, T2>(
            this IEventBuilder<(IOrigin origin, string msg)> eventBuilder,
            Func<IParameterBuilder<string>, IParameterBuilder<T1>> param1,
            Func<IParameterBuilder<string>, IParameterBuilder<T2>> param2)
    {
        return new ParamsBuilder<(IOrigin, T1, T2)>(
            eventBuilder,
            (origin, objs) => (origin, (T1) objs[0], (T2) objs[1]), // ignore this line
            (Parameter<object>) (object) param1(new RootParameterBuilder()).Build(),  // Build() returns Parameter<T1> (e.g. int)
            (Parameter<object>) (object) param2(new RootParameterBuilder()).Build());
    }

Not really important, but in case you need a bit of context, here's some example usage of Params:

        _dispatcher.On // IEventBuilder<IEvent>
            .Chat() // IEventBuilder<(IOrigin, string)>
            .Params( // IEventBuilder<(IOrigin, double)>
                p => p // IParameterBuilder<string>
                    .Transform(Convert.ToInt32) // IParameterBuilder<int>
                    .Transform(i => i + 128.0)) // IParameterBuilder<double>
            .Invoke(t =>
            {
                // t is (IOrigin, double)
            });
snowflake
  • 131
  • 10
  • Can you show Parameter class code? – Evk Nov 02 '17 at 13:18
  • @Evk https://pastebin.com/mMQtvTc0 – snowflake Nov 02 '17 at 13:39
  • Well you are out of luck here it seems. And how exactly you use those `Parameter`? Can't use store them as `object`s? – Evk Nov 02 '17 at 13:55
  • @Evk I need to call `Parameter.ParseFunc(string) : T`. I could do with it returning an object, that is fine. But I store the parsed results in an object[], and then later pass that on to the function marked with `// ignore this line` to give it the proper types back. I know it's a dirty workaround, but I haven't figured out a different way (apart from copy-pasting the 60loc ParamsBuilder class for every amount of parameters.. https://pastebin.com/gibEsJLd And I wouldn't be able to use a loop and argasdhsdf) – snowflake Nov 02 '17 at 20:06
  • 1
    If nothing else helps, you can create parent 'Parameter' class, add ParseFuncUntyped function there and then store your parameters as 'Parameter' objects. You can assign that function in 'Parameter' constructor as ParseFuncUntyped = (s) => ParseFunc(s); Hope you got the idea – Evk Nov 02 '17 at 20:12
  • @Evk That worked! Do you want to make a quick reply to it so I can accept it as a solution? – snowflake Nov 02 '17 at 20:36

2 Answers2

3

If nothing else helps - create Parameter class, move (and adjust) all shared functionality there and inherit Parameter<T> from it. In this case you can move Optional flag and adjust ParseFunc:

public Func<string, object> ParseFuncUntyped {get; protected set;}

Then assign that function in constructor of Parameter<T> and store your parameters as Parameter

Evk
  • 98,527
  • 8
  • 141
  • 191
0

To store a Parameter<int> in a Parameter<object> is not possible. That said, if you make an interface IParameter<T> and make it covariant (IParameter<out T>) you could indeed store an IParameter<int> in an IParameter<object>.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • That's not true actually, because `int` is a struct and covariance does not work for structs. – Evk Nov 02 '17 at 13:53
  • @Evk huh, interesting, I guess I need to do more lowlevel work... never realized that. Will think about the OPs problem some more... – nvoigt Nov 02 '17 at 13:56
  • You might be interested to read this answer and link in it which explains why it works like that: https://stackoverflow.com/a/12454932/5311735 then. – Evk Nov 02 '17 at 13:58