For Answers, see/post comments

Is there an equivalent of MyClass?

No, C# doesn't have an equivalent of VB.NET's MyClass keyword. If you want to guarantee not to call an overridden version of a method, you need to make it non-virtual in the first place.

Why do I need a null test before I invoke a delegate?

Ques: Why do I need a null test before I invoke a delegate?

Ans: If you have an event in a class, you need to add a null test before you call the delegate.
Typically, you would write:

if (Click != null)
Click(arg1, arg2);


There is actually a possible race condition here - the event can be cleared between the first and second line. You would actually want to write:

ClickHandler handler = Click;
if (handler != null)
handler(arg1, arg2);


usually. You might want to do some other sort of synchronization in other scenarios.
So back to the main question. Why is the null test required?


We can't change the existing behavior of calling through a delegate as some apps may depend on it, so it would have to be an addition to the language.

We have talked about adding an Invoke() keyword to the language to make this easier, but after a fair bit of discussion, we decided that we couldn't do the right thing all the time, so we elected not to do anything.

Should I assign null to my local variables?

Q: Should I assign null to my local variables after I use them?

For example:
string s = ...;

Console.WriteLine(s);
s = null;

Ans: There is rarely a need to do this for local variables in C#

The lifetime of variables is tracked by the JIT - it analyzes how variables are used in a routine, and it knows exactly when the variable is no longer needed, and after that point, the value is available to be collected.

Interestingly, if you assign it to null, you are actually extending the lifetime of the variable slightly, so it could cause it to be garbage collected later (though realistically, there's unlikely to be any real difference here.

This is true for the vast majority of methods. If you have a method where your code lives for a while - a loop on a separate thread, for example - then it may be worthwhile to see if there are any unnecessary values living in variables while you wait.

When should I use == and when should I use Equals?

The Equals method is just a virtual one defined in System.Object, and overridden by whichever classes choose to do so. The == operator is an operator which can be overloaded by classes, but which usually has identity behaviour.

For reference types where == has not been overloaded, it compares whether two references refer to the same object - which is exactly what the implementation of Equals does in System.Object.

Value types do not provide an overload for == by default. However, most of the value types provided by the framework provide their own overload. The default implementation of Equals for a value type is provided by ValueType, and uses reflection to make the comparison, which makes it significantly slower than a type-specific implementation normally would be. This implementation also calls Equals on pairs of references within the two values being compared.

However, the main difference between the two types of comparison in normal use (where you're unlikely to be defining your own value types very often) is polymorphism. Operators are overloaded, not overridden, which means that unless the compiler knows to call the more specific version, it'll just call the identity version. To illustrate that, here's an example:


using System;
public class Test
{
static void Main()
{
// Create two equal but distinct strings
string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'});

Console.WriteLine (a==b);
Console.WriteLine (a.Equals(b));

// Now let's see what happens with the same tests but
// with variables of type object
object c = a;
object d = b;

Console.WriteLine (c==d);
Console.WriteLine (c.Equals(d));
}
}

The results are:

True

True

False

True

The third line is False because the compiler can only call the non-overloaded version of == as it doesn't know that the contents of c and d are both string references. As they are references to different strings, the identity operator returns false.


So, when should you use which operator? My rule of thumb is that for almost all reference types, use Equals when you want to test equality rather than reference identity. The exception is for strings - comparing strings with == does make things an awful lot simpler and more readable but you need to remember that both sides of the operator must be expressions of type string in order to get the comparison to work properly.


For value types, I'd normally use == for easier-to-read code. Things would get tricky if a value type provided an overload for == which acted differently to Equals, but I'd consider such a type very badly designed to start with.

Leverage the C# Preprocessor

Like other languages in the C-family, C# supports a set of 'preprocessor' directives, most notably #define, #if and #endif (technically, csc.exe does not literally have a preprocessor as these symbols are resolved at the lexical analysis phase, but no need to split hairs…).

The #define directive allows you to set up custom symbols which control code compilation. Be very aware that unlike C(++), C#'s #define does not allow you to create macro-like code. Once a symbol is defined, the #if and #endif maybe used to test for said symbol. By way of a common example:

#define DEBUG
using System;
public class MyClass
{
public static void Main()
{
#if DEBUG
Console.WriteLine("DEBUG symbol is defined!");
#endif
}
}


When you use the #define directive, the symbol is only realized within the defining file. However if you wish to define project wide symbols, simply access your project's property page and navigate to the "Configuration Properties Build" node and edit the "Conditional Compilation Constants" edit field. Finally, if you wish to disable a constant for a given file, you may make use of the #undef symbol.

How do I get and set Environment variables?

Use the System.Environment class.
Specifically the GetEnvironmentVariable and SetEnvironmentVariable methods.

Admitedly, this is not a question specific to C#, but it is one I have seen enough C# programmers ask, and the ability to set environment variables is new to the Whidbey release, as is the EnvironmentVariableTarget enumeration which lets you separately specify process, machine, and user.

What is the difference between const and static readonly?

The difference is that the value of a static readonly field is set at run time, and can thus be modified by the containing class, whereas the value of a const field is set to a compile time constant.

In the static readonly case, the containing class is allowed to modify it only

  • in the variable declaration (through a variable initializer)
  • in the static constructor (instance constructors, if it's not static)

static readonly is typically used if the type of the field is not allowed in a const declaration, or when the value is not known at compile time.


Instance readonly fields are also allowed.


Remember that for reference types, in both cases (static and instance) the readonly modifier only prevents you from assigning a new reference to the field. It specifically does not make immutable the object pointed to by the reference.

class Program
{
public static readonly Test test = new Test();

static void Main(string[] args)
{
test.Name = "Program";

test = new Test();

// Error: A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)

}
}

class Test
{
public string Name;
}

On the other hand, if Test were a value type, then assignment to test.Name would be an error.

How do I send out simple debug messages to help with my debugging?

Visual Studio offers tons of useful debugging features and allows you to step through your code line-by-line. However, there are times when you don’t want to step through your application, but want to make it output simple text strings with variable values, etc.

Enter the System.Diagnostics.Debug class and its Write* methods. By using the Debug class, you can output messages similarly to the way the Win32 API function OutputDebugString. However, the beauty of the Debug class is that when you build your application using the default Release configuration in Visual Studio, no code lines are generated for your Debug.Write* class. This means there’s no performance penalty for using the Debug class in release code.

To use the Debug class, simply add the “using System.Diagnostics;” statement to your C# code file, and call Debug.Write:Debug.Write("Hello, Debugger!");

In addition to Write, you have the possibility to call WriteIf, WriteLine and WriteLineIf. For
example:

bool @this = true;
bool that = false;
Debug.WriteLineIf(@this that, "A conditional Hello!");


When you are debugging your application under the Visual Studio debugger, all the messages that are sent out by your Write method calls end up in the Output window (View / Output menu command or Ctrl+W,O on the keyboard). However, if you are running your application outside the debugger (say, by starting it from Windows Explorer), you can still view the messages using tools like DebugView from Sysinternals.

Remember, if you build your application using the default Release configuration, even DebugView won’t show your messages because the Debug.Write* calls are eliminated altogether. You can also control code generation by defining the DEBUG conditional directive.

Tip: The .NET debugging/tracing architecture also allows you to redirect debugging messages to different destinations, such as text files. See the help topic “Trace Listeners” for more information.

What release of SQL Server 2005 will run on Windows Vista?

SQL Server 2005 Express Edition with Service Pack 1 will run on Windows Vista but has known issues with User Access Control. For all other editions of SQL Server 2005, Service Pack 2 will be required for Windows Vista and Windows Server "Longhorn" support when those products are released.

Why is SQL Server 2000 (including MSDE) not going to be supported on Windows Vista or Windows Server “Longhorn?”

SQL Server 2005 presents several advances in technology from its predecessor, SQL Server 2000. One such important advancement is the support for patching SQL Server 2005 editions through Windows Update Services, which is not available for MSDE. Similarly, there are several advances in security and performance in the “Longhorn” and “Vista” platforms, such as ‘User Access Control’ that SQL Server 2005 can work with, but that MSDE cannot.

Given these facts, along with the fact SQL Server 2000 (including MSDE) is an aging product nearing the end of its support lifecycle Microsoft decided that its customers would be best served by focusing its resources to test and validate SQL Server 2005 on the new Windows Vista/”Longhorn” platform and provide a clear upgrade path for our SQL Server 2000 (including MSDE) customers to the new SQL Server 2005 platform, rather than invest on making very significant changes to SQL Server 2000 editions to run on Vista.

How are design patterns described?

Typically, a design pattern is described using several of the following items:

  • Pattern name - a brief, descriptive, and unique name to identify the pattern.
  • Classification - a category assignment according to usage (see above).
  • Intent - a description of the goal of the pattern and the reasons for employing it.
  • Also known as (AKA) - patterns are often known by more than one name. Additional names are documented here.
  • Motivation (Forces) - a scenario comprising a problem and a context in which this pattern should be used, i.e. when and where to use this pattern.
  • Applicability - describes various situations (contexts) in which this pattern is usable.
  • Structure - a graphical representation of the pattern, typically in Unified Modeling Language (UML). Primarily, class diagrams and interaction diagrams are used.
  • Participants - a summary of the various classes and objects employed in this pattern and their roles in the design pattern.
  • Collaboration - a description of class and object interactions.
  • Consequences - a description of the results, trade-offs, and any side effects involved in applying this pattern.
  • Implementation - a description of the implementation of the pattern—the pattern "solution". Also provided are notes, suggestions, and techniques helpful in implementing this pattern.
  • Sample code - a source code example of how this pattern can be implemented in a particular programming language.
  • Known uses - a listing of actual usages of this pattern.
  • Related patterns - a listing of related patterns which can be used either in conjunction with or in place of this pattern. Differences between similar patterns are highlighted.

How are design patterns classified?

Design patterns are categorized to facilitate learning and extending them. They are classified in terms of the underlying problems they address, i.e. according to usage.

The three main design pattern categories are:

  • Behavioral design patterns - characterize the manner of class and object interaction and how responsibilities are distributed among them.
  • Creational design patterns - address the object creation process. Creational design patterns encapsulate knowledge about how, when, and by whom an instance is created.
  • Structural design patterns - address the composition of classes and objects.
    Design patterns vary both in granularity and level of abstraction.

What is a design pattern?

A design pattern is a proven design solution to a common problem faced by software developers. Design patterns became popular with the rise of Object Oriented Analysis and Design(OOAD). Design patterns are designed to help developers deliver higher quality, more easily maintained software products in less time and at lower cost.

Design patterns are:

  • encapsulated - They embody design knowledge regarding collaboration of classes and objects, distribution of responsibility, and other design issues.
  • object-oriented - They incorporate OOAD principles—e.g., low coupling, high cohesion.
  • reusable - They are adaptable, flexible, general solutions to classes of problems with broad applicability. Design patterns simplify the task facing the developer.