danielpalme / IocPerformance

Performance comparison of .NET IoC containers
https://danielpalme.github.io/IocPerformance
Apache License 2.0
876 stars 157 forks source link

Resolve instances using generic "Resolve" methods #92

Closed NikolayPianikov closed 6 years ago

NikolayPianikov commented 6 years ago

It makes results more accurate because of there are no any additional operations of conversions of type. Actually it is more sensible scenario to use these methods and all IoC containers have these methods

dadhi commented 6 years ago

Half (or may be more) of container usage cases is integration within other tools, frameworks. Usually it is done by implementing some kind of IResolver interface. The IResolver need to operate with types known at run-time, returning the object and IEnumerable<object>.

I would say that statically known resolved type T is more specialized case than more general run-time object.

Consider this issue, it may interesting to know the performance of Resolve<T>, but rather side by side with Resolve(Type t) instead of replacing it.

This is my IMHO though and up for @danielpalme to decide.

danielpalme commented 6 years ago

@dadhi Correct, and if I remember correctly, then this pull request changed the generic version to the Resolve(Type t) approach: https://github.com/danielpalme/IocPerformance/pull/8

NikolayPianikov commented 6 years ago

Yes I measured that the performance of <T> better then object (rate ~ 3). That is the test:

    class Program
    {
        static void Main(string[] args)
        {
            var count = 10000000;

            MyClass value = new MyClass();
            value = (MyClass)Get(value);
            value = Get<MyClass>(value);

            var stopwatch1 = Stopwatch.StartNew();
            for (int i = 0; i < count; i++)
            {
                value = (MyClass)Get(value);
            }
            stopwatch1.Stop();

            var stopwatch2 = Stopwatch.StartNew();
            for (int i = 0; i < count; i++)
            {
                value = Get<MyClass>(value);
            }
            stopwatch2.Stop();

            Console.WriteLine($"{stopwatch1.ElapsedMilliseconds} / {stopwatch2.ElapsedMilliseconds}");
            Console.ReadLine();
        }

        class MyClass
        {
        }

        static T Get<T>(T value)
        {
            return value;
        }

        static object Get(MyClass myClass)
        {
            return myClass;
        }
    }

For object we have:

      IL_002a: ldloc.1      // 'value'

      IL_002b: call         object ConsoleApp1.Program::Get(class ConsoleApp1.Program/MyClass)

      IL_0030: castclass    ConsoleApp1.Program/MyClass

      IL_0035: stloc.1      // 'value'

For <T> we have:

      IL_0052: ldloc.1      // 'value'

      IL_0053: call         !!0/*class ConsoleApp1.Program/MyClass*/ ConsoleApp1.Program::Get<class ConsoleApp1.Program/MyClass>(!!0/*class ConsoleApp1.Program/MyClass*/)

      IL_0058: stloc.1      // 'value'

The bodies of methods are the same:

    IL_0000: ldarg.0      // 'value'

    IL_0001: ret      

And wach IoC in the test has own `Resolve()'.

NikolayPianikov commented 6 years ago

Another 2 points:

ipjohnson commented 6 years ago

@NikolayPianikov Resolve(Type) is how it's used when integrating with frameworks like asp.net and many other framework so for a lot containers Resolve(Type) is a huge use case and Resolve<T> is not used much.

I agree with @dadhi an additional Resolve<T> test might be interesting if you resolved the exact same types so you could do an apples to apples comparison to Resolve(Type).

NikolayPianikov commented 6 years ago

Well, I agree with the majority. And it is a too small loss of performance. I had a slightly different experience using IoC :) I close the question