Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/NRefactory.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
authorDaniel Grunwald <daniel@danielgrunwald.de>2010-10-20 19:58:20 +0400
committerDaniel Grunwald <daniel@danielgrunwald.de>2010-11-01 15:47:49 +0300
commitde0ea567468af7cccc251b8365b52ae868d52604 (patch)
tree0f3ade4531f962ca604d223cf01421b4486c3fbd /README
parent2ae70eb79b4c2f8a2ccfec71fd51d0bdbacf42da (diff)
README: line-break to 100 cols.
Diffstat (limited to 'README')
-rw-r--r--README345
1 files changed, 191 insertions, 154 deletions
diff --git a/README b/README
index af630794..473cc66f 100644
--- a/README
+++ b/README
@@ -1,154 +1,191 @@
-Overview of the NRefactory library:
-
-ICSharpCode.NRefactory.TypeSystem:
- Contains a language-independent representation of the .NET type system.
-
-ICSharpCode.NRefactory.TypeSystem.Implementation:
- Contains base classes that help implementing the type system interfaces.
-
-ICSharpCode.NRefactory.CSharp.Dom:
- Abstract Syntax Tree for C#
-
-ICSharpCode.NRefactory.CSharp.Resolver:
- Semantic analysis for C#
-
-Null-Object pattern:
- The NRefactory library makes extensive use of the null object pattern.
- As a reult, NullReferenceExceptions should be very rare when working with this library.
- In the type system, both ITypeReference and IType use SharedTypes.UnknownType to represent unknown types.
- Unless the method is documented otherwise, no method or property returning a ITypeReference or IType will return null.
- When adding to this library, to try to keep such uses of null rare.
-
- Note that the null object pattern is not used for ITypeDefinition:
- IProjectContent.GetClass() returns null when a type is not found. Take care to abort your operation or substitute UnknownType
- instead of passing the null to code expecting an IType.
-
- 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 types and type definitions?
-
-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 between types and type references?
- 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.
-
- Because an ArrayType must have an IType as element type, we also need the ArrayTypeReference to represent an array
- of a type that's not yet resolved. When resolved, the ArrayTypeReference produces an array type:
- new ArrayTypeReference(r).Resolve(context) = new ArrayType(r.Resolve(context))
-
-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.
- [Actually, sometimes static state is used for caches, but those uses are thread-safe.]
- 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, internal caches in the library are not used when passing a mutable ITypeResolveContext.
-
- 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.
- It is guaranteed not to change (within the using block), so the library may cache some information. (TODO: give example of a cache)
- Once the return value is disposed, the read-locks are released (and the caches are cleared).
-
-
-Q: What format do the .ToString() methods use?
-
-A: They don't use any particular format. They're merely intended as a debugging aid.
- Currently .ToString() usually matches .ReflectionName, but that may change in the future.
-
-
-Q: Why are there extension methods IType.IsEnum() and IType.IsDelegate(), but no IType.IsStruct() or IType.IsInterface()?
-
-A: Because if you're asking whether a type is a struct, it's very likely that you're asking the wrong question.
- The distinction between class/struct/interface/enum/delegate is important in the world of type definitions, and there's
- ITypeDefinition.ClassType to address this. But the distinction isn't so important in the world of types.
-
- If whatever you are doing works with struct-types, then it likely will also work with enum-types, and also
- with type parameters constraint to be a value-type.
- So instead of asking IsStruct(), you really should be asking: IType.IsReferenceType == false
-
- Enums and delegates are special because you can do special things with those types (e.g. subtract them from each other).
- If you really need to know, you can do "type.GetDefinition() != null && type.GetDefinition().ClassType == WhatIWant" yourself,
- but for the most part you should be fine with IsReferenceType, IsEnum and IsDelegate.
+Overview of the NRefactory library:
+
+ICSharpCode.NRefactory.TypeSystem:
+ Contains a language-independent representation of the .NET type system.
+
+ICSharpCode.NRefactory.TypeSystem.Implementation:
+ Contains base classes that help implementing the type system interfaces.
+
+ICSharpCode.NRefactory.CSharp.Dom:
+ Abstract Syntax Tree for C#
+
+ICSharpCode.NRefactory.CSharp.Resolver:
+ Semantic analysis for C#
+
+Null-Object pattern:
+ The NRefactory library makes extensive use of the null object pattern.
+ As a result, NullReferenceExceptions should be very rare when working with this library.
+ In the type system, both ITypeReference and IType use SharedTypes.UnknownType to represent
+ unknown types.
+ Unless the method is documented otherwise, no method or property returning a ITypeReference or
+ IType will return null.
+ When adding to this library, to try to keep such uses of null rare.
+
+ Note that the null object pattern is not used for ITypeDefinition:
+ IProjectContent.GetClass() returns null when a type is not found. Take care to abort your
+ operation or substitute UnknownType instead of passing the null to code expecting an IType.
+
+ 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 types and type definitions?
+
+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 between types and type references?
+ I've seen lots of duplicated classes (ArrayType vs. ArrayTypeReference, etc.)
+
+A: If you've previously used the .NET Reflection API, the concept of type references will be new
+ to you.
+
+ 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.
+
+ Because an ArrayType must have an IType as element type, we also need the ArrayTypeReference
+ to represent an array of a type that's not yet resolved.
+ When resolved, the ArrayTypeReference produces an array type:
+ new ArrayTypeReference(r).Resolve(context) = new ArrayType(r.Resolve(context))
+
+
+Q: What's in an ITypeResolveContext?
+
+A: An ITypeResolveContext is an environment for looking up namespaces and types.
+ Usually, a resolve context will represent a set of projects.
+ Most of the time, that set will be the current project, plus the direct references of the
+ current project.
+
+ Every project content on its own is a type resolve context (IProjectContent extends
+ ITypeResolveContext); but (with the exception of mscorlib) isn't useful for resolving types as
+ you also need the references.
+ To represent a set of projects, the class CompositeTypeResolveContext can be used.
+
+
+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.
+ [Actually, sometimes static state is used for caches, but those uses are thread-safe.]
+ 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, internal caches in the library are not used when passing a mutable
+ ITypeResolveContext.
+
+ 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.
+ It is guaranteed not to change (within the using block), so the library may cache some
+ information. (TODO: give example of a cache)
+ Once the return value is disposed, the read-locks are released (and the caches are cleared).
+
+
+Q: What format do the .ToString() methods use?
+
+A: They don't use any particular format. They're merely intended as a debugging aid.
+ Currently .ToString() usually matches .ReflectionName, but that may change in the future.
+
+
+Q: Why are there extension methods IType.IsEnum() and IType.IsDelegate(), but no IType.IsStruct()' or IType.IsInterface()?
+
+A: Because if you're asking whether a type is a struct, it's very likely that you're asking the
+ wrong question.
+ The distinction between class/struct/interface/enum/delegate is important in the world of type
+ definitions, and there's ITypeDefinition.ClassType to address this. But the distinction isn't
+ so important in the world of types.
+
+ If whatever you are doing works with struct-types, then it likely will also work with
+ enum-types, and also with type parameters constraint to be a value-type.
+ So instead of asking IsStruct(), you really should be asking: IType.IsReferenceType == false
+
+ Enums and delegates are special because you can do special things with those types
+ (e.g. subtract them from each other).
+ If you really need to know, you can do
+ "type.GetDefinition() != null && type.GetDefinition().ClassType == WhatIWant"
+ yourself, but for the most part you should be fine with IsReferenceType, IsEnum and IsDelegate.