diff options
author | Daniel Grunwald <daniel@danielgrunwald.de> | 2010-10-10 20:15:29 +0400 |
---|---|---|
committer | Daniel Grunwald <daniel@danielgrunwald.de> | 2010-10-10 20:15:29 +0400 |
commit | 9efef610b18befcc639b7f1347be1fb668e4b296 (patch) | |
tree | 2f492c74e09f3d285baf53ed50ae5f744477142b /README | |
parent | c4f4db723b781474d61dca855032ffbb4aa924cb (diff) |
Rename AggregateTypeResolveContext to CompositeTypeResolveContext.
Rename DotNetName to ReflectionName.
Added ReflectionName-parser to ReflectionHelper.
Move the ReaderWriterLock synchronization from TypeStorage to SimpleProjectContent.
Added some documentation to the README.
Diffstat (limited to 'README')
-rw-r--r-- | README | 98 |
1 files changed, 98 insertions, 0 deletions
@@ -26,3 +26,101 @@ Null-Object pattern: The pattern also extends to the C# resolver, which always produces a ResolveResult, even in error cases. Use ResolveResult.IsError to detect resolver errors. Also note that many resolver errors still have a meaningful type attached, this allows code completion to work in the presence of minor semantic errors. + +FAQ: +Q: What is the difference between a type and a type definition? + +A: Basically, a type (IType) is any type in the .NET type system: + - an array (ArrayType) + - a pointer (PointerType) + - a managed reference (ByReferenceType) + - a parameterized type (ParameterizedType, e.g. List<int>) + - a type parameter (ITypeParameter, e.g. T) + - or a type definition (ITypeDefiniton) + + Type definitions are only classes, structs, enums and delegates. + Every type definition is a type, but not every type is a type definition. + NRefactory's ITypeDefinition derives from IType, so you can directly use any type definition as a type. + In the other direction, you could try to cast a type to ITypeDefinition, or you can call the GetDefinition() + method. The GetDefinition() method will also return the underlying ITypeDefinition if given a parameterized type, + so "List<int>".GetDefinition() is "List<T>". + +Q: What is the difference betweent type references and types? + I've seen lots of duplicated classes (ArrayType vs. ArrayTypeReference, etc.) + + NRefactory has the concept of the "project content": every assembly/project is stored independently from other assemblies/projects. + It is possible to load some source code into a project which contains the type reference "int[]" without having to load + mscorlib into NRefactory. + So inside the entities stored for the project, the array type is only referenced using an ITypeReference. + This interface has a single method: + interface ITypeReference { + IType Resolve(ITypeResolutionContext context); + } + By calling the Resolve()-method, you will get back the actual ArrayType. + At this point, you have to provide the type resolution context: + + Note that every type can also be used as type reference - the IType interface derives from ITypeReference. + Every IType simply returns itself when the Resolve()-method is called. + Types are often directly used as references when source and target of the reference are within the same assembly. + +A: If you've previously used the .NET Reflection API, the concept of type references is new to you. + + +Q: How do I get the IType or ITypeReference for a primitive type such as string or int? + +A: Please use: + TypeCode.Int32.ToTypeReference().Resolve(context) + Skip the Resolve() call if you only need the type reference. + + ReflectionHelper.ToTypeReference is very fast if given a TypeCode (it simply looks up an existing type reference in an array), + and your code will benefit from caching of the resolve result (once that gets implemented for these primitive type references). + + Avoid using "context.GetClass(typeof(int))" - this call involves Reflection on the System.Type being passed, + cannot benefit from any caching implemented in the future, and most importantly: it may return null. + And do you always test your code in a scenario where mscorlib isn't contained in the resolve context? + The approach suggested above will return SharedTypes.UnknownType when the type cannot be resolved, so you + don't run into the risk of getting NullReferenceExceptions. + +Q: Is it thread-safe? + +A: This question is a bit difficult to answer. + NRefactory was designed to be usable in a multi-threaded IDE. + But of course, this does not mean that everything is thread-safe. + + First off, there's no hidden static state, so any two operations working on independent data can be executed concurrently. + TODO: what about the C# parser? gmcs is full of static state... + + Some instance methods may use hidden instance state, so it is not safe to e.g use an instance of the CSharp.Resolver.Conversions class + concurrently. Instead, you need to create an instance on every thread. + + In the case of project contents, it is desirable to be able to use them, and all the classes in that project content, + on multiple threads - for example to provide code completion in an IDE while a background thread parses more files and adds + them to the project content. + + For this reason, the entity interfaces (ITypeDefinition, IMember, etc.) are designed to be freezable. Once the Freeze() method is + called, an entity instance becomes immutable and thread-safe. + + Whether an ITypeResolveContext is thread-safe depends on the implementation: + TypeStorage: thread-safe for concurrent reads, but only if it's not written to (see XML documentation on TypeStorage) + CecilProjectContent: immutable and thread-safe + SimpleProjectContent: fully thread-safe + CompositeTypeResolveContext: depends on the child contexts + + Usually, you'll work with a set of loaded projects (SimpleProjectContents) + and loaded external assemblies (CecilProjectContent). + A CompositeTypeResolveContext representing such a set is thread-safe. + + Hoever, some algorithms can become confused if two GetClass() calls with same arguments produce different + results (e.g. because another thread updated a class definition). + Also, there's a performance problem: if you have a composite of 15 SimpleProjectContents and the resolve algorithm + requests 100 types, that's 1500 times entering and leaving the read-lock. + Moreoever, the ITypeResolveContext methods that return collections need to create a copy of the collection. + + The solution is to make the read lock more coarse-grained: + using (var syncContext = compositeTypeResolveContext.Synchronize()) { + resolver.ResolveStuff(syncContext); + } + On the call to Synchronize(), all 15 SimpleProjectContents are locked for reading. + The return value "syncContext" can then be used to access the type resolve context without further synchronization overhead. + Once the return value is disposed, the read-locks are released. + |