Note in Essential.NET.Volume.1.The.Common.Language.Runtime

下面是一些关于阅读<Essential .Net, CLR>的体会, 当时记录在Txt文本中, 现在直接copy上来, 格式可能会有所不适:

 

1. CLR types are uniquely identified by their assembly name/type name pair, but it does not help the programmer to distinction, so we need namespace prefix.
   Assembly A,B, all have type(class) C, compiler considers they are different.
  

2. In general, assemblies that have a public key but do not have a valid signature cannot be loaded or executed.

3. The fields of a type control how memory is allocated. The CLR initializes all static fields to a default value upon allocation. The CLR will also initialize the fields of heap-allocated instances to the default values.
    Class cs = new Class();
    cs.int  ... 0;
    cs.bool ... false;
    cs.ObjectReference ... null;

4. const and readonly
   Const require an initialization expression whose value can be calculated at compile time, access const field by type.
   e.g: public const int MAX_CUSTOMER_AGE = 128 * 365;
   Access: Type.const_field
   Readonly can specify the initial value either by using an initialization expression or simply by assigning to the field inside the type's constructor method at running time, access readonly field by instance.
   e.g: public readonly long created = System.DateTime.Now.Ticks;
   Access: InstanceObject.readonly_field

5. ref and out
   In C#, the default is pass-by-value, and adding either the ref or the out parameter modifier changes the mode to pass-by-reference. Both keywords indicate pass-by-reference; the out keyword also indicates that the initial value of the parameter is undefined.
   e.g: Function(out Class obj)
       {
   Class rev = obj; // error, obj is undefined; If change 'out' to 'ref', pass.
       }

6. Unlike Java's inner classes, nested types in the CLR are always considered static members of the declaring type and are not affiliated with any particular instance.

7. It is important to note that with overloading, the exact method to be invoked is determined at compile time. No runtime tests are performed to determine which overload to choose.

8. When in constructor, the derived constructor's body will not be process until the base constructor is finished.
   When in destructor, when the derived destructor's body is done, the base destructor is to be processing.
   C# is not like C++, when during constructor process in C#, the object is treated as the most-derived class no matter which derived-level is doing now, it means that the virtual method will find the 'right' one in the derived  hierarchy, however, in C++, it will only find the processing-level ones.

9. In C#, the destructor(~Class) is considered as the finalize method.(In C#, you cannot implement the Finalize method directly. Rather, you must implement a destructor, which causes the compiler to emit your destructor code inside a Finalize method followed by a call to your base type's Finalize.)
   When the GC tries to reclaim an object that has a finalizer, the reclamation is postponed until the finalizer can be called. Rather than reclaim the memory, the GC enqueues the object requiring finalization onto the finalization queue. A dedicated GC thread will eventually call the object's finalizer, and after the finalizer has completed execution, the object's memory is finally available for reclamation. This means that objects with finalizers take at least two separate rounds of garbage collection before they are finally collected.
   Using IDisposable, maybe needs SuppressFinalize.

10. The method table has two contiguous regions. The first region is used for virtual methods. The second region is used for nonvirtual methods. The first region will contain one entry for each method that has been declared virtual, both in the current type and in all base types and interfaces(Actually, the entities in this region about the all base types is only the most-base type's all virtual method, for the reason of recursion). The second region will contain one entry for each non-virtual method that is declared in the current type.

11. The difference of virtual method layout strategy between base type and interface inheritance:
    The entity location about base type is beyond interface ones, so we can think base type entity is constructd firstly. When coming to interface, it will first verify the existence of methods, then modify their offset region and the place point to, finally, fix them base on the derived implement.
    Base type: Just copy base type's all virtual method by order to derived type.(Matching routing base on the some method offset)
    Interface: First, derived type has a interface offset table(matching routing base on it), the implement method of interface(public or explict) is all considered as virtual method, so it has a 'newslot' attribute(final), and, if this derived type consider as base type in future, the implement method will be copied even though they are 'final'. The derived type will create one or two entities in virtaul region based on the way of implement(a distinct one in public or explict, two in both).

12. reserve words and attributes mapping
    Ref 6.2, 6.3

13. The resources that are owned by an AppDomain include loaded modules, assemblies, and types. These resources are held in memory as long as the owning AppDomain is loaded. Unloading an AppDomain is the only way to unload a module or assembly. Unloading an AppDomain is also the only way to reclaim the memory consumed by a type's static fields.

14. In particular, an object is scoped to a particular AppDomain, and object references can refer only to objects in the same AppDomain.

15. Every variable must be assigned before used.
    Using 'new' at struct or class type, every field in it will be assigned to default value.
    Just declare local struct variable, you can use the field be assigned before, otherwise will be error; Only have you explicitly assigned all fieldes values then can treat the whole 'object' as parameter, boxing, etc.
 
16  .Net do not allow modify the property of intermedia object, because it looks like never happened yet, and confuse the result.
    E.g: When unboxing a object, it will copy all field from heap and create a new one at stack(copy also happened when boxing), if we do not declare a local variable to restore the stack one and directly set its property values, it gets error(get value do not).

    unboxing-object.field = XXX;  // can't pass complier

    valueType obj  = unboxing-object;    // pass compiler, but will not effect the heap one, because of copy
    obj.field = XXX;

17. All variable(value, object) must be set on stack then to calculate(whole fields struct or just 4bits reference).
    If variable is a reference type, because of none-(un)boxing, all operation is on reference, and effect the given one.
    If variable is a value type, when after boxing or unboxing, operation is on a whole new one, do not effect others.(see tips-16)

18 delegate and event
   1. event is a application of delegate.
   2. when using event in a class as a (public) field, outside this class, it can only use event as a left-operator applying += and -=, and can not directly call event(params), except inside the class.
   3. This is a template when using event: delegate    void    MyEventHandler(object    sender,    MyEventHandler    e);

19 These are two ways to apply asy-call:
   1. Create a new thread.
   2. Using delegate's begininvoke and endinvoke.(Create a delegate object and point it to the method)

20. ==; (Virtual) object.Equals(object); (Static) Equals(object,object); (Static) ReferenceEquals(object, object); (Virtual) object.GetHashCode():
   1. == is a high-level view operation(Implicit), effect on stack; Equals,RefEq and GetHC(Explicit) are considered as a fundamental atomic operation, so we can think that == applying others to implement their function.
   2. A == B -> call Equals(A,B) or call ReferenceEquals(A,B) depend on type of A,B:
      If A & B all are valuetype, ==(Equals) compare their value.(Some valuetype do not allow applying == at its instance.)
      If A & B all are object, ==(ReferenceEquals) compare their address(reference). Except to 'String', which first compare address, then check value.
   3. Equals(A,B) is the same as A.Equals(B), the explicit way we want to verify whether they are considered as equal.
      If we do not override this method, it will act as calling ReferenceEquals() inside.
   4. (Static) ReferenceEquals(Object, Object) is the only explicit way to verify whether they point to the same instance.
   5. GetHashCode() is a method that providing a way treating the object as a 'Key' in HashTable.
      Dictionary<object A, object B> maybe like that Hashtable(A.GetHashCode(), B).
      In default (GetHC relate to ==):
      At object, when two object calculate their HashCode the same, it must be the same instance(RefEq), vice versa;(GetHC relate to RefEq)
      At valuetype, when two instance equal, their hashcode is the same, vice versa;(GetHC relate to Eq) The behavior of the implement of Equals() and GetHashCode() in valuetype is differnet to object. So, we should also override the other method when we override one of them.
      However, we can change the logic of GetHastCode(), and these rules will not run. The principle of this logic, refer to 'Effective c#, tips 10'.

21. string String:
    string is a c# keyword, mapping to type of String in .Netframework.(Wrapper)
    String is a .Netframework type.

 

posted @ 2009-06-02 14:31  Tyrael  阅读(259)  评论(0编辑  收藏  举报