You are on page 1of 23

OOPS CLASS

A class is a programming language construct used to group related fields and method. It describes the rules by which objects behave; these objects are referred to as instances of that class. A class specifies the structure of data (like properties, fields, attributes, data members) within each instance as well as methods which manipulate the data of the object and perform tasks. A class is the most specific type of an object in relation to a specific layer. Fields are variables in a class. By default, a class is a private. Class is the root word of classification. When you design a class, you systematically arrange information into a meaningful entity. This arranging is an act of classification. In C#, you use the class keyword, a name, and a pair of curly braces to define a new class. The data and methods of the class occur in the body of the class, between the curly braces. Example: class Circle { double Area() { return 3.141592 * radius * radius; } double radius; } A class is a definition of type.

OBJECT
An object is the individual run-time unit that is used as the basic building block of programs. An object is an instantiation (instance) of a class. A class is only a blueprint offering a defined functionality. That functionality is actually implemented by creating an instance of that class, in form of an object. To use the functionality of a particular class, an object of that class must be created first. An object is an instance of class type, created when the program runs. Example: Circle c; //create a circle variable c = new Circle(); //initialize it

The new keyword instantiates a class and an object is created of type Circle whose reference is stored in c.

CONSTRUCTOR
When a new keyword is used to create an object, the CLR has to construct an object by using the definition of the class. The CLR has to grab a piece of memory from the operating system, fill it with the fields defined by the class, and then call the constructor to perform any initialization required. A constructor is a special method; it has a same name as the class, it can take parameters, but it cannot return a value (not even a void). Every class must have a constructor. If u dont write one, the compiler automatically generates one. The default constructor is a constructor that doesnt take any parameters. It does not matter whether the compiler generates it or u write it, it is still the default constructor. A non-default constructor is like a default constructor but it can be overloaded (can have parameters). Example: class Circle { public Circle() // default constructor { radius = 0.0; } public Circle(double initialRadius) // overloaded constructor { radius = initialRadius; } public double Area() { return 3.141593 * radius * radius; } private double radius; } If the constructor is private, it cannot be used outside a class, which will prevent u from creating an object from methods that outside a class. If you write your own constructor for a class, the compiler does not generate a default constructor. Therefore, if youve written your own constructor that accepts one or more constructor that accepts one or more parameters and you also want a default constructor, youll have to write the default constructor.

The new operation is atomic, but underneath, object creation is really a two-phase process. First, the new operation has to allocate some raw memory from the heap. You have no control over this phase of an object's creation. Second, the new operation has to convert the raw memory into an object; it has to initialize the object. You can control this phase this by using a constructor.

DESTRUCTOR
Like object creation, object destruction is also a two-phase process. The two phases of destruction exactly mirror the two phases of creation. First, you have to perform some tidying up. You do this by writing a destructor. Second, the raw memory has to be given back to the heap; the memory that the object lived in has to be reallocated. Once again, you have no control over this phase. You can use a destructor to perform any tidying up required when an object is garbage collected. The syntax for writing a destructor is a tilde (~) followed by the name of the class. Example: class Tally { public Tally() { this.instanceCount++; } ~Tally() { this.instanceCount--; } public static int InstanceCount() { return this.instanceCount; } ... private static int instanceCount = 0; } A destructor is a method which is automatically invoked when the object is destroyed. Its main purpose is to clean up and to free the resources which were acquired by the object along its life cycle and unlink it from other objects or resources invalidating any references in the process. Restrictions on destructors: 1) Cannot declare a destructor in a struct coz struct is a value type.

2) Cannot declare access modifier coz u can never call a destructor-the garbage collector does. 3) Destructor cannot have parameters coz u cannot call it. 4) The compiler automatically translates a destructor into an override of Object.Finalize method. The compiler generated Finalize method contains the destructor body inside a try block, followed by a finally block that calls the base class Finalize. This ensures that a destructor always calls its base class destructor. U cant override Finalize nor call it.

ACCESS MODIFIER
Access modifiers are keywords used to specify the declared accessibility of a member or a type. If no access modifier is specified then by default the compiler considers it has private. There are five types of access modifiers in C#: 1) Public: The public keyword is an access modifier for types and type members. The public members have no restriction in accessing. It is the most permissive access level. 2) Private: The private keyword is a member access modifier. The private members are only accessible in the same class. It has the least permissive access level. 3) Protected: The protected keyword is a member access modifier. A protected member is accessible from within the class in which it is declared, and from within any class derived from the class that declared this member. A protected of a base class is accessible in a derived class only on derived class reference i.e. through derived class type. A struct cannot be protected coz it does not support inheritance. 4) Internal: The internal keyword is an access modifier for types and type members. Internal members are accessible only within files in the same assembly. 5) Protected Internal: The members are accessible in the derived class of the base class and also by the other classes of the same assembly. It is used only for classes. Access modifiers are not allowed on namespaces. Namespaces have no access restrictions. Top-level types, which are not nested into other types, can only have internal or public accessibility. The default accessibility for these types is internal.

The default for a class and struct is private. The default for an enum and interface is public. The accessibility domain of a member specifies where, in the program sections, a member can be referenced. If the member is nested within another type, its accessibility domain is determined by both the accessibility of the member and the accessibility domain of the immediately containing type.

STRUCTURES
In some cases, the class can contain so little data that the overhead of managing the heap becomes disproportionate. In these cases it is better to define the type as a structure. Because structures are stored on the stack, the memory management overhead is often reduced (as long as the structure is reasonably small). A structure can have its own fields, methods, and constructors just like a class (and unlike an enumeration), but it is a value type and not a reference type. In C#, the primitive numeric types int, long and float are structures. To declare your own structure value type, you use the struct keyword followed by the name of the type, followed by the body of the structure between opening and closing braces. Example: struct Time { public int hours, minutes, seconds; } As with classes, making the fields of a structure public is not advisable in most cases; there is no way to ensure that public fields contain valid values. A better idea is to make the fields private and provide your structure with constructors and methods. By default, structure is private. Use structs for lightweight concepts where it makes sense to copy the value, and use classes for more heavyweight concepts where it doesn't make sense to copy the value. Difference between class and struct: A structure and a class are syntactically very similar but there are a few important differences.

1) You can't declare a default constructor (a constructor with no parameters) for


a struct. The reason you can't declare your own default constructor in a struct is because the compiler always generates one. In a class, the compiler generates the default constructor only if you don't write a constructor yourself. The compiler-generated default constructor for a structure always sets the fields to 0, false, or nulljust like for a class. Therefore, you should

ensure that a structure value created by the default constructor behaves logically and makes sense with these default values. If you don't want to use these default values, you can initialize fields to different values by providing a non-default constructor. However, if you don't initialize a field in the constructor, the compiler won't initialize it for you. This means you must explicitly initialize all the fields in all the structure constructors or you'll get a compile-time error. 2) In a class, you can initialize instance fields at their point of declaration. In a struct, you cannot. Any initialization should be done from the non-default constructor. 3) Structure does not support inheritance. U cannot use a struct type variable after it is declared. It has to be initialized with a new keyword i.e. a constructor should be called to initialize the variable. Also u cannot initialize or assign one struct variable to another without initializing the variable that has to be copied or assigned. When you copy a struct variable, each field on the left side is copied directly from its corresponding field on the right side. This copying is done as a fast single-block copy that never throws an exception. In case of a class, if youve to make a copy of a variable then both the variables refer to the same object.

INHERITANCE (MULTIPLE)
Inheritance is a way to form new classes using classes that have already been defined. The new classes, known as derived classes, take over (or inherit) attributes and behavior of the pre-existing classes, which are referred to as base classes (ancestor). It is intended to help reuse existing code with little or no modification. By default, inheritance is public and it only allows public access. The syntax for declaring that a class inherits from another class is as follows: class DerivedClass : BaseClass { ... } The derived class inherits from the base class. In C# a class is allowed to derive from, at most, one other class; a class is not allowed to derive from two or more classes. However, unless DerivedClass is declared as sealed, you can create further derived classes that inherit from DerivedClass using the same syntax: class DerivedSubClass : DerivedClass { ... } A derived class automatically contains all fields from the base class. These fields require initialization when an object is created. Therefore, the constructor for a derived class must call the constructor for its base class.

Example: class IdentifierToken : Token { public IdentifierToken(string name) : base(name) // calls Token(name) { ... } ... } If you don't explicitly call a base class constructor in a derived class constructor, the compiler attempts to silently insert a call to the base class's default constructor. This works because System.Object has a public default constructor. However, not all classes have a public default constructor, in which case forgetting to call the base class constructor results in a compile-time error, because the compiler must insert a call to a constructor, but does not know which one to use. It is possible to refer to an object from a variable of a different type as long as the type used is a class that is higher up the inheritance hierarchy i.e. a super class can refer to its subclass object but subclass cannot refer a super class object. Even though, a super class can refer a subclass object it cannot look into all the subclass methods. It can only look into those methods which are common to both super and subclasses. Only subclass reference will allow access to all methods of its class. By default the super class methods are accessed when they are referred.

VIRTUAL
If a base class and a derived class happen to declare two methods that have the same signature (the method signature is the name of the method and the number and types of its parameters), you will receive a warning when you compile the application. The method in the derived class masks (or hides) the method in the base class that has the same signature. However, if you're sure that you want the two methods to have the same signature, you can silence the warning by using the new keyword as follows: class Token { ... public string Name() { ... } } class IdentifierToken : Token { ... new public string Name() { ... } }

Using the new keyword like this does not change the fact that the two methods are completely unrelated and that hiding still occurs. It just turns the warning off. To avoid this, a virtual keyword is used where the subclass method will override the super class method for future extensions. A method that is intended to be overridden is called a virtual method. You can mark a method as a virtual method by using the virtual keyword. A C# method is not virtual by default. Example: namespace System { class Object { public virtual string ToString() { ... } ... } ... } Virtual methods allow you to call different versions of the same method, based on the type of the object determined dynamically by the runtime. it is useful for a base class to allow derived classes to access some of its members, while hiding these same members from classes that are not part of the hierarchy. In this situation, you can use the protected keyword to tag members.

OVERRIDDING
Overriding a method is a mechanism for providing different implementations of the same methodthe methods are all related because they are intended to perform the same task. Hiding a method is a means of replacing one method with another the methods are usually unrelated and might perform totally different tasks. Overriding a method is a useful programming concept; hiding a method is probably an error. If a base class declares that a method is virtual, a derived class can use the override keyword to declare another implementation of that method. Example: class IdentifierToken : Token { ...

public override string Name() { ... } } There are some important rules you must follow when declaring polymorphic methods by using the virtual and override keywords:

1) You're not allowed to declare a private method by using the virtual or


override keyword. 2) The two methods must be identical. That is, they must have the same name, the same parameter types, and the same return type. 3) The two methods must have the same access. 4) You can only override a virtual method. If the base class method is not virtual and you try to override it. 5) If the derived class does not declare the method by using the override keyword, it does not override the base class method. 6) An override method is implicitly virtual and can itself be overridden in a further derived class.

INTERFACE
An interface allows you to completely separate the name of a method from its implementation. The interface tells you only what the name, return type, and parameters of the method are. Exactly how the method is implemented is not a concern of the interface. The interface represents how you want an object to be used, rather than how it happens to be implemented at a particular moment in time. To declare an interface, you use the interface keyword instead of the class or struct keyword. Inside the interface, you declare methods exactly as in a class or a struct, except that you never specify an access modifier (no public, private, or protected access), and you replace the method body with a semicolon. Example: interface IComparable { int CompareTo(object obj); } You preface the name of your interfaces with a capital I. The restrictions on interfaces are u cannot have fields (not even static fields), constructors, destructors, access modifier, nest types (enum, structs, classes, interfaces, delegates) inside an interface. You cannot use inherit an interface.

To implement an interface, you declare a class or struct that inherits from the interface and implements all the interface methods. Example: class Token : IToken { ... string IToken.Name() { ... } } Here IToken is an interface defines as interface IToken { string Name(); } When you implement an interface, you must ensure that each method matches its corresponding interface method exactly i.e. 1) The method names and return types match 2) Any parameters declared match even the ref and out parameters. 3) The method name is prefaced by the name of the interface. This is known as explicit interface implementation. 4) If you are using explicit interface implementation, the method should not have an access qualifier. All methods implementing an interface are publicly accessible. If there is any difference between the interface definition and its declared implementation, the class will not compile. Advantages of Explicit Interface implementation: A method defined by using explicit interface implementation cannot be declared as virtual, whereas omitting the interface name allows this behavior. Without using explicit interface implementation it would not be possible to distinguish which method implements part of which interface if multiple interfaces contain methods with the same names, return types, and parameters. A class can extend another class and implement an interface at the same time. In this case, C# does not distinguish between the base class and the interface by using keywords as Java does. The base class is named first, followed by a comma, followed by the interface.

You can reference an object by using a variable defined as an interface that its class implements. Multiple Inheritances: A class can have at most one base class, but is allowed to implement an unlimited number of interfaces. A class must still implement all the methods it inherits from all its interfaces. An interface is not allowed to inherit from any kind of class, but an interface is allowed to inherit other interfaces. Example: class IdentifierToken : DefaultTokenImpl, IToken, IVisitable { ... }

ABSTRACT CLASS
Interfaces could be implemented by many different classes. Hence its quite common for parts of the derived classes to share common implementations. To avoid the repetition of code is build a new class with the common implementation. This is a good solution but not the right one. The best method is to use abstraction of common functionality. To declare that you're not allowed to create instances of a class, you must explicitly declare that the class is abstract, by using the abstract keyword. Example: abstract class DefaultTokenImpl { public DefaultTokenImpl(string name) { this.name = name; } public string Name() { return name; } private string name; } An abstract class is all about common implementation, whereas an interface is all about usage. Abstract class cannot be instantiated but can only be inherited. Abstract class must be overridden. An abstract class internally is a virtual method.

SEALED CLASS
Using inheritance is not always easy and requires forethought. If you create an interface or an abstract class, you are knowingly writing something that will be inherited from in the future. Unless you consciously design a class with the intention of using it as a base class, it's extremely unlikely that it will function very well as a base class. Fortunately, C# allows you to use the sealed keyword to prevent a class from being used as a base class if you decide that it should not be. Example: sealed class LiteralToken : DefaultTokenImpl, IToken { ... } A sealed class cannot declare any virtual methods. The sole purpose of the virtual keyword is to declare that this is the first implementation of a method that you intend to override in a derived class, but a sealed class cannot be derived from. A sealed class does not allow a programmer to use the class as a base class, meaning the programmer cannot derive a new class from it nor the method can be overridden. Sealed classes add another level of strictness during compile-time, improve memory usage and trigger certain optimizations that improve run-time efficiency. Sealed method: You can also use the sealed keyword to declare that an individual method is sealed. This means that a derived class cannot then override the sealed method. You can only seal an override method.

ABSTRACTION
Abstraction is the facility to define objects that represent abstract "actors" that can perform work, report on and change their state, and "communicate" with other objects in the system. The term information hiding refers to the hiding of state details, but extending the concept of data type from earlier programming languages to associate behavior most strongly with the data, and standardizing the way that different data types interact, is the beginning of abstraction. When abstraction proceeds into the operations defined, enabling objects of different types to be substituted, it is called Polymorphism. When it proceeds in the opposite direction, inside the types or classes, structuring them to simplify a complex set of relationships, it is called Delegation or Inheritance.

POLYMORPHISM (LATE BINDING OR DYNAMIC BINDING)

Polymorphism lets you treat derived class members just like their parent classs members. Polymorphism is the ability of objects belonging to different types to respond to method calls of the same name, each one according to an appropriate type-specific behavior. The programmer (and the program) does not have to know the exact type of the object in advance, so this behavior can be implemented at run time. This is called late binding or dynamic binding. In practical terms, polymorphism means that if class B inherits from class A, it doesnt have to inherit everything about class A; it can do some of the things that class A does differently. This means that the same verb can result in different actions as appropriate for a specific class, so controlling code can issue the same command to a series of objects and get appropriately different results from each one. Overloading Polymorphism is the use of one method signature, or one operator such as "+", to perform several different functions depending on the implementation. The "+" operator, for example, may be used to perform integer addition, float addition, list concatenation, or string concatenation. Any two subclasses of Number, such as Integer and Double, are expected to add together properly in an OOP language. The language must therefore overload the concatenation operator, "+", to work this way. This helps improve code readability.

OVERLOADING
If two identifiers have the same name and are declared in the same scope, they are said to be overloaded. Overloading is primarily useful when you need to perform the same operation on different data types. You can overload a method when the different implementations have different sets of parameters; that is, when they have the same name but a different number of parameters, or when the types of the parameters differ. This capability is allowed so that, when you call a method, you can supply a comma-separated list of arguments, and the number and type of the arguments is used by the compiler to select one of the overloaded methods. However, note that although you can overload the parameters of a method, you can't overload the return type of a method. In other words, you can't declare two methods with the same name that differ only in their return type.

GARBAGE COLLECTION GC CONCEPTS


Object creation is really a two-phase process. First, the new operation has to allocate some raw memory from the heap. You have no control over this phase of an object's creation. Second, the new operation has to convert the raw memory into

an object; it has to initialize the object. You can control this phase this by using a constructor. An object can have as many references as possible. The runtime has to keep track of all these references. If the one of the reference disappears (by going out of scope), other references (such as ref) might still exist. Therefore, the lifetime of an object cannot be tied to a particular reference variable. An object can only be destroyed when all the references to it have disappeared. Like object creation, object destruction is also a two-phase process. The two phases of destruction exactly mirror the two phases of creation. First, you have to perform some tidying up. You do this by writing a destructor. Second, the raw memory has to be given back to the heap; the memory that the object lived in has to be reallocated. Once again, you have no control over this phase. The process of destroying an object and returning memory back to the heap is known as garbage collection. In C#, you can never destroy an object yourself. There just isn't any syntax to do it. If it was your responsibility to destroy objects, sooner or later one of the following situations would arise: 1) You'd forget to destroy the object. This would mean that the object's destructor (if it had one) would not be run, tidying up would not occur, and memory would not be reallocated back to the heap. You could quite easily run out of memory.

2) You'd try to destroy an active object. If a class held a reference to a destroyed object, it would be a dangling reference. The dangling reference would end up referring either to unused memory or possibly to a completely different object in the same piece of memory. Either way, the outcome of using dangling reference would be undefined. 3) You'd try and destroy the same object more than once. This might or might not be disastrous, depending on the code in the destructor. Instead, the garbage collector is responsible for destroying objects for you. The garbage collector guarantees the following:
1) Each object will be destroyed and its destructors run. When a program ends,

all outstanding objects will be destroyed.


2) Each object is destroyed exactly once. 3) Each object is destroyed only when it becomes unreachable; that is, when no

references refer to the object.

The garbage collector runs in its own thread and can execute only at certain times (typically when your application reaches the end of a method). While it runs, other threads running in your application will temporarily halt. This is because the garbage collector may need to move objects around and update object references; it cannot do this while objects are in use. The steps that the garbage collector takes are as follows: 1) It builds a map of all reachable objects. It does this by repeatedly following reference fields inside objects. The garbage collector builds this map very carefully and makes sure that circular references do not cause an infinite recursion. Any object not in this map is deemed to be unreachable. 2) It checks whether any of the unreachable objects has a destructor that needs to be run (a process called finalization). Any unreachable object that requires finalization is placed in a special queue called the freachable queue (pronounced F-reachable). 3) It deallocates the remaining unreachable objects (those that don't require finalization) by moving the reachable objects down the heap, thus defragmenting the heap and freeing memory at the top of the heap. When the garbage collector moves a reachable object, it also updates any references to the object. 4) At this point, it allows other threads to resume. 5) It finalizes the unreachable objects that require finalization (now in the freachable queue) in a separate thread.

FINALIZE & DISPOSE FINALIZE


You can use a destructor to perform any tidying up required when an object is garbage collected. The syntax for writing a destructor is a tilde (~) followed by the name of the class. For example, here's a simple class that counts the number of live instances by incrementing a static count in the constructor and decrementing a static count in the destructor: class Tally { public Tally() { this.instanceCount++; } ~Tally() { this.instanceCount--; }

public static int InstanceCount() { return this.instanceCount; } ... private static int instanceCount = 0; } There are some very important restrictions that apply to destructors: 1) You cannot declare a destructor in a struct. A struct is a value type that lives on the stack and not the heap, so garbage collection does not apply. struct Tally { ~Tally() { ... } // compile-time error } 2) You cannot declare an access modifier (such as public) for a destructor. This is because you never call the destructor yourselfthe garbage collector does. public ~Tally() { ... } // compile-time error 3) You never declare a destructor with parameters, and it cannot take any parameters. Again, this is because you never call the destructor yourself. ~Tally(int parameter) { ... } // compile-time error The compiler automatically translates a destructor into an override of the Object.Finalize method. The compiler translates the following destructor: class Tally { ~Tally() { ... } } Into this: class Tally { protected override void Finalize() { try { ... } finally { base.Finalize(); } } } The compiler-generated Finalize method contains the destructor body inside a try block, followed by a finally block that calls the base class Finalize. This ensures that

a destructor always calls its base class destructor. It's important to realize that only the compiler can make this translation. You can't override Finalize yourself and you can't call Finalize yourself.

DISPOSE
Sometimes it's inadvisable to release a resource in a destructor; some resources are just too valuable and too scarce to lie around unreleased for arbitrary lengths of time. Scarce resources need to be released, and they need to be released as soon as possible. In these situations, your only option is to release the resource yourself. A disposal method is a method that disposes of a resource. If a class has a disposal method, you can call it explicitly and thereby control when the resource is released. The using statement provides a clean mechanism for controlling the lifetimes of resources. You can create an object, and this object will be destroyed when the using statement block finishes. The syntax for a using statement is as follows: using ( type variable = initialization ) embeddedStatement Example: using (TextReader reader = new StreamReader(filename)) { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); } }

This using statement is precisely equivalent to the following translation:


{ TextReader reader = new StreamReader(filename); try { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); } } finally { if (reader != null) { ((IDisposable)reader).Dispose();

} } }

The variable you declare in a using statement must be of a type that implements the IDisposable interface. The IDisposable interface lives in the System namespace and contains just one method called Dispose:
namespace System { interface IDisposable { void Dispose(); } } When writing a class, should you write a destructor, or implement the IDisposable interface? A call to a destructor will happen but you just don't know when. On the other hand you know exactly when a call to the Dispose method happens, but you just can't be sure that it will actually happen, because it relies on the programmer remembering to write a using statement. However, it is possible to ensure that the Dispose method always runs by calling it from the destructor. This acts as a useful backup.

INTERVIEW QUESTIONS
Does C# support multiple-inheritance? Yes. Who is a protected class-level variable available to? It is available to any sub-class (a class inheriting this class). Are private class-level variables inherited? Yes, but they are not accessible. Although they are not visible or accessible via the class interface, they are inherited. Describe the accessibility modifier protected internal. It is available to classes that are within the same assembly and derived from the specified base class. Whats the top .NET class that everything is derived from? System.Object Will the finally block get executed if an exception has not occurred? Yes. Whats the C# syntax to catch any possible exception? A catch block that catches the exception of type System.Exception. You can also omit the parameter data type in this case and just write catch {}.

Why is it a bad idea to throw your own exceptions? Well, if at that point you know that an error has occurred, then why not write the proper code to handle that error instead of passing a new Exception object to the catch block? Throwing your own exceptions signifies some design flaws in the project. Can multiple catch blocks be executed for a single try statement? No. Once the proper catch block processed, control is transferred to the finally block (if there are any). Can you prevent your class from being inherited by another class? Yes. The keyword sealed will prevent the class from being inherited. Can you allow a class to be inherited, but prevent the method from being over-ridden? Yes. Make the method sealed. Whats an abstract class? A class that cannot be instantiated. An abstract class is a class that must be inherited and have the methods overridden. An abstract class is essentially a blueprint for a class without any implementation. When do you absolutely have to declare a class as abstract? 1. When the class itself is inherited from an abstract class, but not all base abstract methods have been overridden. 2. When at least one of the methods in the class is abstract. What is an interface class? Interfaces, like classes, define a set of properties, methods, and events. But unlike classes, interfaces do not provide implementation. They are implemented by classes, and defined as separate entities from classes. Why cant you specify the accessibility modifier for methods inside the interface? They all must be public, and are therefore public by default. Can you inherit multiple interfaces? Yes. .NET does support multiple interfaces. Whats the difference between an interface and abstract class? In an interface class, all methods are abstract - there is no implementation. In an abstract class some methods can be concrete. In an interface class, no accessibility modifiers are allowed. An abstract class may have accessibility modifiers.

What is the difference between a Struct and a Class? Structs are value-type variables and are thus saved on the stack, additional overhead but faster retrieval. Another difference is that structs cannot inherit. Whats the implicit name of the parameter that gets passed into the set method/property of a class? Value. The data type of the value parameter is defined by whatever data type the property is declared as. What does the keyword virtual declare for a method or property? The method or property can be overridden. How is method overriding different from method overloading? When overriding a method, you change the behavior of the method for the derived class. Overloading a method simply involves having another method with the same name within the class. Can you declare an override method to be static if the original method is not static? No. The signature of the virtual method must remain the same. (Note: Only the keyword virtual is changed to keyword override) What are the different ways a method can be overloaded? Different parameter data types, different number of parameters, different order of parameters. If a base class has a number of overloaded constructors, and an inheriting class has a number of overloaded constructors; can you enforce a call from an inherited constructor to a specific base constructor? Yes, just place a colon, and then keyword base (parameter list to invoke the appropriate constructor) in the overloaded constructor definition inside the inherited class. When should you call the garbage collector in .NET? As a good rule, you should not call the garbage collector. However, you could call the garbage collector when you are done using a large object (or set of objects) to force the garbage collector to dispose of those very large objects from memory. However, this is usually not a good practice. How do you convert a value-type to a reference-type? Use Boxing. What happens in memory when you Box and Unbox a value-type? Boxing converts a value-type to a reference-type, thus storing the object on the heap. Unboxing converts a reference-type to a value-type, thus storing the value on the stack.

What does Dispose method do with the connection object? Deletes it from the memory What is garbage collection? Garbage collection is a system whereby a run-time component takes responsibility for managing the lifetime of objects and the heap memory that they occupy. This concept is not new to .NET - Java and many other languages/runtimes have used garbage collection for some time. Is it true that objects don't always get destroyed immediately when the last reference goes away? Yes. The garbage collector offers no guarantees about the time when an object will be destroyed and its memory reclaimed. Why doesn't the .NET runtime offer deterministic destruction? Because of the garbage collection algorithm. The .NET garbage collector works by periodically running through a list of all the objects that are currently being referenced by an application. All the objects that it doesn't find during this search are ready to be destroyed and the memory reclaimed. The implication of this algorithm is that the runtime doesn't get notified immediately when the final reference on an object goes away - it only finds out during the next sweep of the heap. Futhermore, this type of algorithm works best by performing the garbage collection sweep as rarely as possible. Normally heap exhaustion is the trigger for a collection sweep. Is the lack of deterministic destruction in .NET a problem? It's certainly an issue that affects component design. If you have objects that maintain expensive or scarce resources (e.g. database locks), you need to provide some way for the client to tell the object to release the resource when it is done. Microsoft recommend that you provide a method called Dispose() for this purpose. However, this causes problems for distributed objects - in a distributed system who calls the Dispose() method? Some form of referencecounting or ownership-management mechanism is needed to handle distributed objects - unfortunately the runtime offers no help with this. Does non-deterministic destruction affect the usage of COM objects from managed code? Yes. When using a COM object from managed code, you are effectively relying on the garbage collector to call the final release on your object. If your COM object holds onto an expensive resource which is only cleaned-up after the

final release, you may need to provide a new interface on your object which supports an explicit Dispose() method. I've heard that Finalize methods should be avoided. Should I implement Finalize on my class? An object with a Finalize method is more work for the garbage collector than an object without one. Also there are no guarantees about the order in which objects are Finalized, so there are issues surrounding access to other objects from the Finalize method. Finally, there is no guarantee that a Finalize method will get called on an object, so it should never be relied upon to do clean-up of an object's resources. Microsoft recommend the following pattern: public class CTest : IDisposable { public void Dispose() { ... // Cleanup activities GC.SuppressFinalize(this); }

~CTest() {

// C# syntax hiding the Finalize() method

Dispose(); } } In the normal case the client calls Dispose(), the object's resources are freed, and the garbage collector is relieved of its Finalizing duties by the call to SuppressFinalize(). In the worst case, i.e. the client forgets to call Dispose(), there is a reasonable chance that the object's resources will eventually get freed by the garbage collector calling Finalize(). Given the limitations of the garbage collection algorithm this seems like a pretty reasonable approach. Do I have any control over the garbage collection algorithm?

A little. For example, the System.GC class exposes a Collect method - this forces the garbage collector to collect all unreferenced objects immediately.

How can I find out what the garbage collector is doing? Lots of interesting statistics are exported from the .NET runtime via the '.NET CLR xxx' performance counters. Use Performance Monitor to view them.

You might also like