2

Here's a link to the previous question I had, which led me to this one. C# Nested foreach loop optimization

There is still high computation time, and I'm not sure what the cause is.

object foo;
List<string> StringList = new List<string>(); // Populated by previous code
Dictionary<string, Type> assemblyTypes = RandomAssembly.GetTypes().ToDictionary(t => t.Name, t => t);

  foreach (String name in StringList)
  {                     
    if (assemblyTypes.ContainsKey(name))
    {
      // Create an instance of the matching class and add it
      // to the appropriate lists.
      Type at = assemblyTypes[name];
      foo = Activator.CreateInstance(at);       
      ArbitraryList1.Add(foo);
    }
  }    
Community
  • 1
  • 1
sburke1988
  • 73
  • 1
  • 5
  • ANTZ Profiler is pretty good at these sorts of problems, and they have a free trial. – Mike Christensen Oct 11 '11 at 21:52
  • 3
    Activator.CreateInstance is quite slow. – Deleted Oct 11 '11 at 21:53
  • 5
    (1) Reflection is not free. Often, it's not even cheap. `Activator.CreateInstance(at)` will always be significantly slower than `new Whatever()`. (2) if your assembly has a million types in it, of course it's going to take a lot longer than if it has 5. (3) We don't know what type of objects you're creating -- in particular, whether they take a long time to create. In short, there's *not even nearly enough info here* to diagnose "high computation time". – cHao Oct 11 '11 at 21:54
  • 1
    If perf is critical, maybe look into building an IL emitter.. – Mike Christensen Oct 11 '11 at 21:55
  • How many types are in that assembly? – bryanmac Oct 11 '11 at 22:10
  • I agree with Mike. The [NInject](http://ninject.org/) framework uses exactly this approach to avoid calling constructors via reflections each time. In fact, you might want to look into using a framework like [NInject](http://ninject.org/), [MEF](http://msdn.microsoft.com/en-us/library/dd460648.aspx), etc to solve your higher level problem instead of creating custom code. – Merlyn Morgan-Graham Oct 11 '11 at 22:11
  • Create the object from the assemblies on demand (when they are used) instead. – Magnus Oct 11 '11 at 22:12

3 Answers3

3

If the computation time is noticeably slow I guess you're calling into this code a lot and you're newing up a lot of objects that you don't know much about at compile time.

Instead of keeping the classes in a Dictionary<string, type> and call CreateInstance you want to keep a dictionary of their constructors Dictionary<string, ConstructorInfo> so you can call them directly without having to look for it every time with reflection.

That way you can just call AssemblyConstructors[Name].Invoke() to create a new instance of the class.

This way you only have to use reflection once to find the constructors.

// keep a dictionary of constructors (instead of the types)
var Constructors = new Dictionary<string, ConstructorInfo>();            

// add this class to this dictionary
Type t = typeof(SomeClass);            
string name = t.Name;
Constructors[name] = t.GetConstructors()[0]; // use reflection only once here, afterwards we reuse the reflected info

// new up an instance 
var o = Constructors[name].Invoke(new object[] {}); 

I think the first constructor will be the parameterless one. Else try something like t.GetConstructors().Where(x => x.GetParameters().Count() == 0).First(); This is the fastest easy way I know because apparently you can't get a delegate to a constructor.

If you write the classes you're newing up yourself, you can have a common base class or interface with a method that creates one, that way you can keep a delegate to that constructor, that's even faster.

This post also has some interesting ideas about this that take optimization much further. If you want to do this fast, you can. Almost as fast as just calling new KnownClass()

Good luck,

GJ

Community
  • 1
  • 1
gjvdkamp
  • 9,929
  • 3
  • 38
  • 46
1

Summary: essentially unbounded loop with one of the slowest functions in the framework called in each iteration will be slow.

There are multiple approaches to avoid reflection, but without any other information you just have to live with it.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • The slowest function isn't called in each loop. It's surrounded with an if check. Presumably, there's many many more types then there are types that they want to activate. I would worry more about iterating over the many many non matched types. – bryanmac Oct 11 '11 at 22:53
0

Use Dictionary.TryGetValue to look up the "name" key once instead of twice. This is just a little tip as I am sure reflection is the bottleneck.

Frank Hileman
  • 1,159
  • 9
  • 19