Coding Guidelines For Extensions
This page contains guidelines for Pex extension writers.
Be aware of instrumentation
An important fact needs to stay in the mind of the implementor when doing so:
- any BCL class used in the extension might be instrumented, which deteriorates it's performance.
To counter this effect, different solutions are possible:
- Do not use that particular API.
- Use the 'SafeXXX' counterpart of 'XXX' that ships with Extended Reflection.
- (The name prefix 'Safe' has a historical reason: in the beginning, Extended Reflection had no mechanism to deal with re-entrance problems, and using any instrumented class by the monitoring code was fatal. This is no longer the case, but using any method that has been instrumented comes with a big performance penalty.)
- When using a debug build of Extended Reflection, you can generate a log file and inspect the listings of calls to instrumented methods.
- use the safe collections, e.g. SafeDictionary<,> instead of Dictionary<,>.
- use the safe debug assertions and assumptions (pre-conditions), e.g. SafeDebug.AssumeNotNull(foo);
- use SafeDebugger.Break() to break
- use SafeString instead of String,
- use SafeStringBuilder instead of StringBuilder
- use SafeStringWriter instead of StringWriter; however, consider using StringBuilder instead since it is more lightweight
- When your code might be called from instrumented code, and you don't want that your code is monitored, wrap it into a disposable _ProtectingThreadContext. This disables monitoring callbacks.
// your code
- test your extension using a debug build of Pex; it contains assertions that indicate early if you misused an API
- prefer IIndexable<T>, ICountable<T> or ICopyable<T> to IEnumerable<T>
- consider using IFiniteSet<T>, or IFiniteMap<T> to represent immutable data sets and maps
- do not (implicitly) cast an array to IEnumerable<T> (or IList<T>, ICollection<T>), since enumerating over the array involving a helper class that gets instrumented!
- use Indexable, Set, Map, Enumerable to create collections
- use lazy allocations
- use Extended Reflection metadata instead of System.Reflection, for example TypeEx t = Metadata<Foo>.Type;