ROOT.NET is better than a completely dynamic language (like pyROOT), but it is slower than straight C++ bindings. ROOT is written in C++ – each time you call a ROOT function your context must switch from the .NET world to the C++ world. For some things this is very cheap – like a float or an int or a double. But for other things it can be fairly expensive – for example, a string. Or a ROOT object. Keep this in mind when you design your .NET code – try to minimize the transitions, or if you have expensive ones see if you can do them up front (or in a separate thread).

Some speed measurements were done on version v2.4 for CHEP 2012. For simple conversions, like calling TH1F::Fill, the .NET version of ROOT ran at about 66% of the speed for the C++ version. If you involved strings (say setting a TAxis label over and over) then it ran at about 40% of the straight C++ speed. Finally, if you are using the current dynamic interface it is a dog – even pyROOT beast ROOT.NET.

Of course, there is the old adage: don’t optimize early! The interface is quite fast – definitely a lot faster than using python on Linux. So, explore and worry when you run into a problem.


In general, ROOT is a raw-metal machine. It freely passes around pointers to arrays and other objects (just look at how many void*’s there are). The .NET world just has no analog to this. As a result, if you are used to using ROOT in a C++ world, keep your eyes open anytime the ROOT interface contains a pointer or an array. The handling is likely to be non-optimal for the translation!

  • Any method that returns a pointer to int’ or double, etc. will be converted to a NetArrayTranslator object in the .NET world. This is a seriously dangerous object! In general, the translator has no idea how many int’s or long’s that the pointer points to. So the NetArrayTranslator can just access the n’th – even if the n’th is beyond the end of the array (whatever it is). Ugh!!!
  • If there is a data field that is a pointer (for example, TArrayC::fArray), you can run into real trouble if you set the data field. The ROOT.NET layer will be very happy to let do that – (setting it to a char[]), but it will allocate a temporary C++ object to do it, which will be “gone” by the time the call is done – leaving the TArrayC pointing off into space. This is a bug – the translator should not allow this. However, I have no currently implemented a x-check on this.

Corner Cases

There are lots of small things and cases that just don’t translate well – or easily. These are often things that could be done with some effort, but that, for whatever reason, I have not done. This is not an exhaustive list…

  • Fixed size arrays are not, in general, handled. For example, if a data member is fData[8][3] (see TBuffer3D for an example), it won’t get translated.
  • If the translation has different input and output objects (i.e. a float*) then only the getter will exist on a data field. This is because .NET doesn’t allow different types for the get/set method, and I’ve made the decision to favor “get” over “set”.


.NET has very specific meanings for how .Equals, “==”, and GetHashCode work and interact. ROOT.NET does not always follow these rules. In most cases this is fine – when dealing with a generic C++ ROOT object, the proper rules are followed and you can expect everything, including maps, to work correctly. However, if the C++ object defines the “operator==” method, then do not expect all of these rules to be followed. I haven’t worked out a good heuristic for this, but if you have ideas let me know!

Object Tracking

There are multiple ways to get the same object back from ROOT. For example, you can use TFile::Get to get the same object twice. In ROOT.NET you should get back the same wrapper object. Unfortunately, that is not currently what happens. While the infrastructure does exist for this, this isn’t happening properly yet.

Last edited Aug 30, 2012 at 12:40 PM by gwatts, version 8


krishnateja Apr 27, 2013 at 6:10 AM 
How to save a h.ShowBackground(80, "") into another histo ?