I am a developer at Microsoft and work in the .NET Common Language Runtime (CLR) team. For the last 4 years I have been working on virtual machine technologies on a variety of form factors including desktops (Windows, Linux), tablets (Win8), gaming-consoles (Xbox 360), mobile devices (Windows Phone 7, Windows CE, Symbian).I have worked on various core pieces of the runtime including Garbage Collector, memory manager, platform abstraction layer, runtime-performance, etc.Before working on .NET I worked on Visual Studio Team Foundation Server, Visual Studio Team System, Adobe Framemaker, Adobe Acrobat, Texas Instrument's Code Composer Studio.
I saw two posts on Enums today on Eric Lipperts and Chris Rathjen's blog. Enums are significantly different from the other types and people run into unusal problems while working with them.
C++
The CLI enum is considerably different from the native C++ enum and therefore you need to be careful how you define and use them in Managed C++. In new syntax (C++/CLI whidbey) the following code compiles even though both the enums define the same name Cool.
enum class Coolness // class indicates this is a C++/CLI enum{ NotSoCool, Cool, SuperCool};enum class TempRange { Cool, Hot, VeryHot,};
enum
{
NotSoCool,
Cool,
SuperCool
};
Hot,
VeryHot,
In old syntax (pre whidbey) you need to define the enum as __value enum Coolness. In case you drop the class then you are using the native C++ enum and according to C++ specification the enumerator declarations are promoted to the same scope as the enumerated type declaration and the code will fail to compile pointing out a redefinition of Cool.
C#
In C# we do need not care about these as there is only one definition of enum which is that of the CLI enum.
Common things like the first enum member get the value 0, the value of a subsequent member is calculated by adding 1 to the member textually preceeding it, you can assign values explicitely to a enum member are well-known. However there are some not so well known usages as well.
enum Coolness : byte{ NotSoCool = 5, Cool, VeryCool = NotSoCool + 7, SuperCool}Coolness coolType = Coolness.VeryCool;Console.WriteLine("Underlying type: {0}", Enum.GetUnderlyingType(coolType.GetType()));Console.WriteLine("Type Code : {0}", coolType.GetTypeCode());Console.WriteLine("Value : {0}", (byte)coolType);
NotSoCool = 5,
VeryCool = NotSoCool + 7,
Coolness
Console
By default the compiler uses Int32 to store the enum members. Here we are asking it to use byte. VeryCool uses a reference to the NotSoCool and will get the value 12. So the out put of the code above will be
Underlying type: System.ByteType Code : ByteValue : 12
Since all enums have System.Enum as the abstract base type, a lot of funcionality becomes available to get details about the enum type.
If you want to print the value of the enum then it can be done in the following ways
Console.WriteLine(coolType.ToString("G")); // name of the constantConsole.WriteLine(coolType.ToString("F")); // name of the constantConsole.WriteLine(coolType.ToString("X")); // value is hexConsole.WriteLine(coolType.ToString("D")); // value in decimal Output:VeryCool VeryCool 0C 12
F and G gives the same value in this case. They differ based on whether FlagsAttribute is applied to it.
You can also get a array filled with either the value (GetValues) or names (GetNames) of all the constants in the enum.
string[] names = Enum.GetNames(typeof(Coolness));int index = 0;foreach (Coolness coolVal in Enum.GetValues(typeof(Coolness))){ Console.WriteLine("{0,-10} => {1}", names[index++], coolVal.ToString("D"));}
string
coolVal.ToString(
}
This prints
NotSoCool => 5Cool => 6VeryCool => 12SuperCool => 13
You can also query the name of the constant in the enum that has the specified value or whether a value is defined in the enum or not. The following will print cool and 5 is not defined.
Console.WriteLine(Enum.GetName(typeof(Coolness), 6)); if(!Enum.IsDefined(typeof(Coolness), (byte)7)) Console.WriteLine("5 is Not Defined");
Overriding ToString()
You cannot override the ToString of the enum type. So in case you wanted to display "Not so cool" instead of NotSoCool when someone called ToString on your enum type then you cannot do that simply by overriding the ToString.
This is a common issue that comes up frequently when you want to show values in reports, web pages, XML where you want to put in human readable text for enum values. Commonly people use non-generic solution of maintaining arrays of these descriptions and get text out of them by indexing using the enum value or some other things like storing it in a hashtable and using the ToString value as the key to get the desciption out.
A generic solution would be to apply custom attributes on the enum constants and write static methods to get the desciption. See the modified code below
using System;using System.Reflection;namespace FunWithEnum{ enum Coolness : byte { [Description("Not so cool")] NotSoCool = 5, Cool, // since description same as ToString no attr are used [Description("Very cool")] VeryCool = NotSoCool + 7, [Description("Super cool")] SuperCool } class Description : Attribute { public string Text; public Description(string text) { Text = text; } } class Program { static string GetDescription(Enum en) { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false); if (attrs != null && attrs.Length > 0) return ((Description)attrs[0]).Text; } return en.ToString(); } static void Main(string[] args) { Coolness coolType1 = Coolness.Cool; Coolness coolType2 = Coolness.NotSoCool; Console.WriteLine(GetDescription(coolType1)); Console.WriteLine(GetDescription(coolType2)); } }}
using
namespace
[
Text = text;
Using this approach is pretty generic because for all enum constants that have this attribute applied to it, the desciption will be picked up from it and for those that do not have the attribute the common ToString() method will be called to get the description. However, the GetDescription uses reflection and can be slow.
The method shown above needs an explicit method call. If you prefer enum.GetDescription() then you need to use extension method as outlined here.
<Updated the sources to add logging and default file index.html handling. Now the code is about 90 lines :(>
I decided to write a http-server in Ruby on Windows to see how much code it requires as I have been reading about how Ruby gets your work done much easily and much faster. Some of the new things in C# 2.0 /3.0 have been already around in Ruby for some time and they make coding in Ruby fun and very interesting. I'll share my experiences about a some of the features in Ruby that I'd like to see in C#.
This is a no-frills minimal implementation which any hacker can break in about 15 minutes :) So I deployed it over the intranet. I hosted my personal site from http://www.geocities.com/basuabhinaba on the server and it worked first time. The code below should work without much modifications, just replace the IP address xxx.xxx.xxx.xxx to the one on your machine. I was amazed at how soon I was able to code this thing up in Ruby (doesn't say much about code quality though :) )
Features
Issues
Finally the Code
It took me about 70 lines of code to get this to work.
require 'socket' class HttpServer def initialize(session, request, basePath) @session = session @request = request @basePath = basePath end def getFullPath() fileName = nil if @request =~ /GET .* HTTP.*/ fileName = @request.gsub(/GET /, '').gsub(/ HTTP.*/, '') end fileName = fileName.strip unless fileName == nil fileName = @basePath + fileName fileName = File.expand_path(fileName, @defaultPath) fileName.gsub!('/', '\\') end fileName << "\\index.html" if File.directory?(fileName) return fileName end def serve() @fullPath = getFullPath() src = nil begin if File.exist?(@fullPath) and File.file?(@fullPath) if @fullPath.index(@basePath) == 0 #path should start with base path contentType = getContentType(@fullPath) @session.print "HTTP/1.1 200/OK\r\nServer: Makorsha\r\nContent-type: #{contentType}\r\n\r\n" src = File.open(@fullPath, "rb") while (not src.eof?) buffer = src.read(256) @session.write(buffer) end src.close src = nil else # should have sent a 403 Forbidden access but then the attacker knows that such a file exists @session.print "HTTP/1.1 404/Object Not Found\r\nServer: Makorsha\r\n\r\n" end else @session.print "HTTP/1.1 404/Object Not Found\r\nServer: Makorsha\r\n\r\n" end ensure src.close unless src == nil @session.close end end def getContentType(path) #TODO replace with access to HKEY_CLASSES_ROOT => "Content Type" ext = File.extname(path) return "text/html" if ext == ".html" or ext == ".htm" return "text/plain" if ext == ".txt" return "text/css" if ext == ".css" return "image/jpeg" if ext == ".jpeg" or ext == ".jpg" return "image/gif" if ext == ".gif" return "image/bmp" if ext == ".bmp" return "text/plain" if ext == ".rb" return "text/xml" if ext == ".xml" return "text/xml" if ext == ".xsl" return "text/html" end end def logger(message) logStr = "\n\n======================================================\n#{message}" puts logStr $log.puts logStr unless $log == nil end basePath = "d:\\web" server = TCPServer.new('XXX.XXX.XXX.XXX', 9090) logfile = basePath + "\\log.txt" $log = File.open(logfile, "w+") loop do session = server.accept request = session.gets logStr = "#{session.peeraddr[2]} (#{session.peeraddr[3]})\n" logStr += Time.now.localtime.strftime("%Y/%m/%d %H:%M:%S") logStr += "\n#{request}" logger(logStr) Thread.start(session, request) do |session, request| HttpServer.new(session, request, basePath).serve() end end log.close
In many situation when something fails (exception is thrown) in the try block you want to retry that again. This could be a network timeout exception, or some other resource unavailability where you expect the same piece of try block code to succeed if you execute it again.
How you do it in Ruby
Let us assume there is some networkAccess() function which sometime throws a TimeoutException. In Ruby you can write code as follows.
begin # try in C# networkAccess() rescue Exception => ex #same as catch (Exception ex) in c# retry puts "Finally quiting" end
Here the retry keyword makes the preceeding try block (starting with begin in case of Ruby) to be executed again. This code can be further enhanced to create a custom Exception class which has a public attribute which is used to inform the caller whether it can call the failing routine again. In ruby this'd be
class TimeoutException < Exception attr :okToRetry # public attribute in C# def initialize(value) # constructor in c# @okToRetry = value end end // simulate a network access failure which succeeds on 3rd attempt def networkAccess() $val += 1 raise TimeoutException.new($val < 3) #throw new TimeoutException end $val = 0 begin networkAccess() rescue TimeoutException => ex #catch (TimeoutException ex) retry if ex.okToRetry puts "Finally quiting" end
Here the failing callee function networkAccess raises (throws) an exception using a public attribute in the exception class to signal the caller to indicate if it can be called again.
In C#
In C# unfortunately (??) there is no support for retry. We can debate whether it'd be useful, but I feel it would make the exception handling more complete and expressive if it did. There are two workarounds. One is using goto :) and other is what we notmally use, by converting the exception to a return value and calling the failed routine again based on that.
TryLabel:try{ downloadMgr.DownLoadFile("file:///server/file", "c:\\file"); Console.WriteLine("File successfully downloaded");}catch (NetworkException ex){ if (ex.OkToRetry) goto TryLabel;}
TryLabel:
downloadMgr.DownLoadFile(
If you compare this with the retry in Ruby the difference in the expressiveness is evident.
The other options is to create a wrapper around this call and convert the exception to some return code and call that wrapper again based on whether its ok to call the failing function
public static bool Wrapper(DownloadManager downloadMgr){ try { downloadMgr.DownLoadFile("file:///server/file", "c:\\file"); return true; } catch (NetworkException ex) { Console.WriteLine("Failed to download file: {0}", ex.Message); return (!ex.OkToRetry); } }static void Main(string[] args){ while (!Wrapper(downloadMgr)) ;}
public
static
Here the wrapper converts the failure in DownloadFile to false return code and the caller goes on calling wrapper as long as return code is false.
<Edit: See the extended discussion at the end of which I conclude Anonymous methods are indeed lexical closures!!! >
Anonymous methods in C# are just anonymous methods and do not represent true lexical closure. There are a lot of samples and code out there explaining why. I use a simple example in my mind to remember why it is not the same.
First lets see how the sample works in a language like Ruby which implements true lexical closure.
$arr = Array.new# function funcGen fills the array arr with generated # functions (closures) that print an integer i. i varies # from 0 to val (10) when the function is generateddef funcGen(val) 0.upto(val) do |i| # same as for(i=0;i<val;i++) $arr[i] = Proc.new { # Proc.new creates the closure print i # body of the closure print ' ' } endendfuncGen(10) # call funcGen to fill the array# each function in the array arr is called to print# the value of i$arr.each do |val| val.callend
$arr = Array.new
# function funcGen fills the array arr with generated
# functions (closures) that print an integer i. i varies
# from 0 to val (10) when the function is generated
def
0.upto(val)
$arr[i] = Proc.new {
print i
print
end
funcGen(10)
# the value of i
$arr.each
val.call
Definition of closure requires that the lexical state of the closure when it's created is preserved. So all the variables (environment) used by the closure at the timeof its creation should be captured at a point in time. Since Ruby implementes true closure and it does this the result of running the above code is
0 1 2 3 4 5 6 7 8 9 10
If we see the same sample in C# it'll be some thing like
using System;namespace AnonymousMethod{ delegate void Func(); class Program { static Func[] funcArr = new Func[10]; static void fillFunc(int count) { for (int i = 0; i < count; i++) { funcArr[i] = delegate() { Console.Write("{0} ", i); }; } } static void Main(string[] args) { fillFunc(funcArr.Length); for (int i = 0; i < funcArr.Length; i++) { funcArr[i](); } } }}
funcArr[i] =
fillFunc(funcArr.Length);
funcArr[i]();
However, even though the same logic as in Ruby is implemented in this C# code the result is totally different and is
10 10 10 10 10 10 10 10 10 10
So in this case the value of i when the anonymous method was created is NOT used and the last modified value of i is used. This clearly indicates that lexical environment of all these methods are not closed. In anonymous methods these read-only variables are shared between the outer method and all the other anonymous mehtods. This sample can be tweaked a little to get it to match that of Ruby. The modified sample is as below with all changes marked in bold
using System;namespace AnonymousMethod{ delegate void Func(); class Program { static Func[] funcArr = new Func[10]; static void fillFunc(int count) { for (int i = 0; i < count; i++) { int j = i; funcArr[i] = delegate() { Console.Write("{0} ", j); }; } } static void Main(string[] args) { fillFunc(funcArr.Length); for (int i = 0; i < funcArr.Length; i++) { funcArr[i](); } } }}
With this change in code the output will get changed and will be the same as the Ruby program (0 1 2 3 4 5 6 7 8 9). The difference in the result further strengthens the fact that true closure is not implemented by C#. Inspection of the generated assembly with Reflector clearly shows why...
In either case to encapsulate the anoymous method and the variable i it referes to the compiler generates a class
[CompilerGenerated]private sealed class <>c__DisplayClass2{ public <>c__DisplayClass2(); public void <fillFunc>b__0() { Console.Write("{0} ", this.i); } public int i;}
[CompilerGenerated]
Console.Write(
The method in bold is the anonymous method.
In the first case while parsing the fillFunc method the compiler sees the following code
for (int i = 0; i < count; i++){ funcArr[i] = delegate() { Console.Write("{0} ", i); };}
funcArr[i] = delegate()
Console.Write("{0} ", i);
and figures out that a variable i from the outer scope is used by the anonymous method and the compiler emits the following code
private static void fillFunc(int count){ Func func1 = null; Program.<>c__DisplayClass2 class1 = new Program.<>c__DisplayClass2(); class1.i = 0; while (class1.i < count) { if (func1 == null) { func1 = new Func(class1.<fillFunc>b__0); } Program.funcArr[class1.i] = func1; class1.i++; }}
private
class1.i = 0;
func1 =
class1.i++;
It is obvious from this code that only one object class1 of the generated class is created and is shared between all the anonymous methods and the loop generating the methods. So if anyone of the methods are called later, the last modified value of i (= 10) will be returned.
For the second case on seeing
static void fillFunc(int count){ for (int i = 0; i < count; i++) { int j = i; funcArr[i] = delegate() { Console.Write("{0} ", j); }; }}
for (int i = 0; i < count; i++)
int j = i;
Console.Write("{0} ", j);
The compiler generates the following code
private static void fillFunc(int count){ for (int num1 = 0; num1 < count; num1++) { Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1(); class1.j = num1; Program.funcArr[num1] = new Func(class1.<fillFunc>b__0); }}
Program.<>c__DisplayClass1 class1 =
class1.j = num1;
Program.funcArr[num1] =
Here the class used to encapsulate the anonymous method is very similiar to the one used in the first case. However, since the method uses a variable inside the loop, for each iteration a new object is created. This results is each anonymous methods having its own copy of the object and hence the value of j in it is same as it was at the time of the method creation.
Lets consider I have a class Employee which has Name and JobGrade fields. I want to overload the comparison operators for this class so that it can participate in all types of comparison including <. <=, ==, >=, != and Equals. I want to translate the comparison in-between two Employee objects to be a comparison between the JobGrade . Since I do not want to write the comparison logic each time, typically I'd implement the comparison in one method and from comparison operator overloading methods call this common method. So in C# I'd do something like.
class Employee{ public Employee(string name, int jobGrade){ Name = name; JobGrade = jobGrade; } public string Name; public int JobGrade; public static bool operator <(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) < 0; } public static bool operator >(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) > 0; } public static bool operator ==(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) == 0; } public static bool operator !=(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) != 0; } public override bool Equals(object obj){ if (!(obj is Employee)) return false; return this == (Employee)obj; } public static bool operator <=(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) <= 0; } public static bool operator >=(Employee emp1, Employee emp2){ return Comparison(emp1, emp2) >= 0; } public static int Comparison(Employee emp1, Employee emp2){ if (emp1.JobGrade < emp2.JobGrade) return -1; else if (emp1.JobGrade == emp2.JobGrade) return 0; else if (emp1.JobGrade > emp2.JobGrade) return 1; return 0; }}
class
Name = name;
JobGrade = jobGrade;
This is kind of huge as I have to overload each comparison operator individually even though what I want is to just make Employee object comparable to any other Employee object. What happens is as follows
This makes overloading operators individually a requirement.
What if
In some languages like Ruby and also Perl (I am not that sure on perl) there is a concept of space ship operator <=>. This operator must return less than 0, equal to 0, greater than 0 based on whether the expression on the left is less than, equal-to or greater than that on the right (similiar to IComparable:CompareTo). If C# compiler supports the concept of the space-ship operator then we can simply overload this one operator and expect the compiler to emit code to call this operator for all comparison. So if C# supports this then the above code would look like
class Employee{ public Employee(string name, int jobGrade){ Name = name; JobGrade = jobGrade; } public string Name; public int JobGrade; public override bool Equals(object obj){ if (!(obj is Employee)) return false; return this == (Employee)obj; } // same in the lines of IComparable:CompareTo public static int operator <=>(Employee emp1, Employee emp2){ if (emp1.JobGrade < emp2.JobGrade) return -1; else if (emp1.JobGrade == emp2.JobGrade) return 0; else if (emp1.JobGrade > emp2.JobGrade) return 1; return 0; }}
public override bool Equals(object obj){
if (!(obj is Employee)) return false;
return this == (Employee)obj;
// same in the lines of IComparable:CompareTo
public static int operator <=>(Employee emp1, Employee emp2){
if (emp1.JobGrade < emp2.JobGrade)
return -1;
else if (emp1.JobGrade == emp2.JobGrade)
return 0;
else if (emp1.JobGrade > emp2.JobGrade)
return 1;
In this case what'll happen is as follows
Interfaces like IComparable already exists which needs the class to implement CompareTo which works exactly like <=> operator overloaded as above. If only the compiler directly made calls to this then the need for one to implement this interface and then make calls to this method gets removed.
The overloaded <=> acts as a filler. In case <= and => are already overloaded for a class then calls are made to these methods and for operators not overloaded like == and != calls are made to <=>.
Its not important (atleast to me) how we achieve this and can include ways like have a method CompareTo in Object in the same lines of Equals and make the compiler emits calls to it based on the operator getting used or use explicite <=> operator overloading. Either way the need to overload all 5 operators should be eliminated.
The fact that a struct can implement an interface is well known and so is the fact that casting a value type into an interface leads to boxing of the value type. This is because methods in interfaces are defined as virtual and to resolve virtual references, vtable (method table) look up is required. Since value types do not have pointers to vtable they are first boxed into a reference type and then the look up happens.
This boxing leads to some performance penalty. See Rico Mariani's performance quiz for an example.
The fact that such boxing takes place on casting to interfaces can lead to subtle issues in code. Consider the following
interface IPromotion { void promote();}struct Employee : IPromotion { public string Name; public int JobGrade; public void promote() { JobGrade++; } public Employee(string name, int jobGrade) { this.Name = name; this.JobGrade = jobGrade; } public override string ToString() { return string.Format("{0} ({1})", Name, JobGrade); }}class Program{ static void Main(string[] args) { Employee employee = new Employee("Cool Guy", 65); IPromotion p = employee; Console.WriteLine(employee); p.promote(); Console.WriteLine(employee); }}
interface
JobGrade++;
p.promote();
Here the output would be Cool Guy (65)Cool Guy (65)So even after calling p.promote() the value of JobGrade in employee does not increase. The reason is that on implicitly casting employee to IPromotion p a temporary boxed object is created and p.promote updates the JobGrade in this temporary object and not on original employee value type. Since after this usage the temporary boxed object is not refered to, the update to it is lost and it is garbage collected.
If however we change the code and make Employee a class the output would become as expected
Cool Guy (65)Cool Guy (66)
The reason being that now the boxing does not take place and the update happens on the original employee object.
The recommendation for string comparison has been updated for Whidbey (Visual Studio 2005) and there is an excellent MSDN article on this. One of the highlights is the introduction of the clear cut enumeration that can be passed into most string comparison methods to indicate the kind of comparison you are trying to make.
[Serializable][ComVisible(true)]public enum StringComparison{ CurrentCulture = 0, CurrentCultureIgnoreCase = 1, InvariantCulture = 2, InvariantCultureIgnoreCase = 3, Ordinal = 4, OrdinalIgnoreCase = 5,}
CurrentCulture = 0,
CurrentCultureIgnoreCase = 1,
InvariantCulture = 2,
InvariantCultureIgnoreCase = 3,
Ordinal = 4,
OrdinalIgnoreCase = 5,
The recommendation also states that for culture-agnostic comparisons use the Ordinal and OrdinalIgnoreCase comparisons. These are fast and also safe. They rely on byte matching and are excellent options for matching strings for internal (non-UI) processing.
string.Compare(str1, str2, StringComparison.Ordinal);
With the introduction of the guidelines, developers have become defensive and have started looking for all code that compare string and re-coding them to meet the guidelines. Let's take a look at the most common culture-agnostic string matching used in code and see if they are safe.
string.Equals(string1, string2)
Default interpretation for equals is Ordinal so using this is fine. In case of using any other type of comparison use in the lines of string.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);
string1 == string2
In accordance to the class library design guidelines the == operator for string is overloaded and the implementation is same as for string.Equals. So this is equivalent of calling string.Equals(string1, string2, StringComparison.Ordinal) which is also fine.
switch(string1)
For small sized switch blocks of the form
string myStr = "Abhinaba";// ...switch (myStr){ case "Abhinaba": Console.WriteLine("switch match"); break; default: Console.WriteLine("switch did not match"); break;}
// ...
the code is compiled into
if ((myStr!= null) && (myStr == "Abhinaba")){ Console.WriteLine("switch match");}else{ Console.WriteLine("switch did not match");}
Console.WriteLine("switch match");
Console.WriteLine("switch did not match");
So this is also fine and the comparison will be a string.Equals( strA, strB, StringComparison.Ordinal) comparison.
However, if the switch block is larger then things get complicated. A dictionary is created and lookup happens through Dictionary.TryGetValue with the string as the key. Lookup happens using code similar to
int num1 = this.comparer.GetHashCode(key) & 0x7fffffff;for (int num2 = this.buckets[num1 % this.buckets.Length]; num2 >= 0; num2 = this.entries[num2].next){ if ((this.entries[num2].hashCode == num1) && this.comparer.Equals(this.entries[num2].key, key)) { return num2; }}
A quick look and a bit of poking around with reflector indicates that the result will ultimately be the same as string.Equals( strA, strB, StringComparison.Ordinal).
InvariantCulture
As the guideline suggests replace all InvariantCulture usage with either Ordinal or OrdinalIgnoreCase
Be on the Safe Side
The above discussion was mainly to figure out what to make out of common string comparison statements in existing code. Going forward I think its best to be defensive and clear in code and explicitly call the comparison methods and pass the correct StringComparison enumeration constant.
In my previous blog I was trying to address the issue that when ToString is called on an enum the literal string for the enum constant is returned. Custom attributes can be used to tag localizable description string to the constants so that you can write functions that use reflection to get to the attribute and show that string. However this has a significant disadvantage as you need to write code as follows
enum Coolness { [DescriptionAttribute("Not so cool")] NotSoCool = 5, [DescriptionAttribute("Very cool")] VeryCool = NotSoCool + 7,}class Program{ static string GetDescription(Enum en) { // Uses reflection to get the attribute and returns it } static void Main(string[] args) { Coolness coolType = Coolness.VeryCool; Console.WriteLine(GetDescription(coolType)); }}
static void Main(string[] args)
Coolness coolType = Coolness.VeryCool;
Calling GetDescription method on the enum is definitely not intuitive. This is why I had said that I love extension methods. Converting this to use C#3.0 extension method makes its intuitive and it'll be easy for the developer to remember that in the same lines as ToString there is also a ToDescription on enums.
using System;using System.Reflection;using System.Collections.Generic;using System.Text;using System.Query;using System.Xml.XLinq;using System.Data.DLinq;using System.ComponentModel;// C# 3.0 syntax used...namespace FunWithEnum{ enum Coolness { [DescriptionAttribute("Not so cool")] NotSoCool = 5, Cool, // since description same as ToString no attr are used [DescriptionAttribute("Very cool")] VeryCool = NotSoCool + 7, [DescriptionAttribute("Super cool")] SuperCool } static class ExtensionMethods { public static string ToDescription(this Enum en) //ext method { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes( typeof(DescriptionAttribute), false); if (attrs != null && attrs.Length > 0) return ((DescriptionAttribute)attrs[0]).Description; } return en.ToString(); } } class Program { static void Main(string[] args) { Coolness coolType1 = Coolness.Cool; Coolness coolType2 = Coolness.NotSoCool; Console.WriteLine(coolType1.ToDescription()); Console.WriteLine(coolType2.ToDescription()); } }}
// C# 3.0 syntax used...
[DescriptionAttribute(
false);
if (attrs != null && attrs.Length > 0)
return ((DescriptionAttribute)attrs[0]).Description;
return en.ToString();
class Program
Coolness coolType1 = Coolness.Cool;
Coolness coolType2 = Coolness.NotSoCool;
Console.WriteLine(coolType1.ToDescription());
Console.WriteLine(coolType2.ToDescription());
Frequently while designing classes that have methods which accept enums as parameters, a common question arrises on where to define the enum. Whether to define it inside the class or in the same level as the class.
Lets consider a class Folder which has a method List. It accepts a enum Filter and based on it prints the name of all files or directories in the Folder. We can define the enum at the same level as the Folder as below
enum Filter{ File, Dir}class Folder{ public Folder(string path) { /* ... */ } public void List(Filter filter) { /* ... */ }}Folder folder = new Folder("c:\");folder.List(Filter.File);
File,
Dir
Folder
folder.List(
Or define it inside the Folder class as in
class Folder{ public enum Filter { File, Dir } public Folder(string path) { /* ... */ } public void List(Filter filter) { /* ... */ }} Folder folder = new Folder(@"c:\");folder.List(Folder.Filter.File);
I think that the first approach is much simpler because otherwise you have to continually type in the complete scope of the enum as Folder.Filter . This soon becomes painfull. I first had a little difficulty understanding why do people still do this. Then I figured out that there are a lot of C++ programmers who have migrated to C# and in un-managed C++ the second approach is the way to go. Lets see why
The issue with C++
If we use the same code in C++ as in the first approach then we get the following
/* 1 */ namespace MyNameSpace/* 2 */ {/* 3 */ enum Filter/* 4 */ {/* 5 */ File,/* 6 */ Dir/* 7 */ };/* 8 */ /* 9 */ //char File[] = "c:\\foo\\bar";/* 10 */ class Folder/* 11 */ {/* 12 */ public:/* 13 */ Folder(char* path) { /* ... */ }/* 14 */ void List(Filter filter) { /* ... */ }/* 15 */ };/* 17 */ }
/* 1 */
/* 2 */
/* 3 */
/* 4 */
/* 5 */
/* 6 */
/* 7 */
/* 8 */
/* 9 */
/* 10 */
/* 11 */
/* 12 */
/* 13 */
/* 14 */
/* 15 */
/* 17 */
According to C++ spec the enum constant File and Dir is raised to the same scope as that of Filter. So effectively nowhere in the whole namespace of MyNameSpace can variables of name File or Dir can be defined. So if you uncomment the 9th line then compilation will fail indicating redeclaration of variable File.
So defining enums at the level of classes have serious consequence of namespace pollution. So C++ programmers generally put the enum declaration inside the class definition. This requires the client program to use scope resolution a bit too much even then this is worth the extra typing.
However, in C# since this is a non-issue the enum must be declared at the same level as the class.
class Employee{ //...}class Program{ static int Func(Employee emp) { return emp.Id; } static string Func(Employee emp) { return emp.Name; }}
//...
However, CIL does support overloading methods by return types, even though C#, VB does not . To implement convertion operator overloading C# compiler uses this feature (I know of one usage and I'm sure that there are more :) )
Conversion Operator Overloading and return types
In the following code we are overloading the conversion operator for Employee class so that the class can be easily converted (casted) to string or int.
class Employee{ public string Name; public int Id; public static explicit operator int (Employee emp) { return emp.Id; } public static explicit operator string (Employee emp) { return string.Format("{0} ({1})", emp.Name, emp.Id); }}Employee employee = new Employee("Abhinaba Basu", 23567);Console.WriteLine((int)employee);Console.WriteLine((string)employee);
public static explicit operator int (Employee emp) {
return emp.Id;
public static explicit operator string (Employee emp) {
return string.Format("{0} ({1})", emp.Name, emp.Id);
Employee
Inspection of the Employee class in the assembly with ILDasm or reflector reveals that there are two methods in it which are generated by the compiler.
.method public hidebysig specialname static string op_Explicit(class ConversionOperator.Employee emp) cil managed
.method public hidebysig specialname static int32 op_Explicit(class ConversionOperator.Employee emp) cil managed
Both these methods are identical other than the return types (one returns a string the other an int). So CIL does support method overloading when the methods differ by return types.
#line pre-processor directive, though not commonly used is very interesting. This directive makes the compiler report line numbers for source files differently. If you have the directive #line 1 on the 3nd line of a source file then the compiler will interpret the next line (4th) as the 1st line and will emit all error messages and any other kind of output messages based on this modified line numbering. You can also make the compiler report the source filename differently by giving the name of a file within quotes after the line number.
If you try to compile the following piece of code
/* 1 */ using System;/* 2 */ #line 1 "coolFile.cs"/* 4 */ namespace LineDirective // treated as 1/* 5 */ { // treated as 2/* 6 */ class Program // treated as 3/* 7 */ { // treated as 4/* 8 */ static void Main(string[] args) // treated as 5/* 9 */ { // treated as 6/* 10 */ Invalid syntax; // treated as 7/* 11 */ throw new Exception("Bang");// treated as 8/* 12 */ }/* 13 */ }/* 14 */ }
#line
then even though the compilation failure happens for the junk string on the 10th line in the file program.cs the compiler will report failure on line 7 in the file coolFile.c
Error 1 The type or namespace name 'Invalid' could not be found (are you missing a using directive or an assembly reference?) c:\MyStuff\Code\C#\LineDirective\LineDirective\coolFile.cs 7 13 LineDirective
The compiler also stores this modified line numbering in the pdb and so if you comment out the junk string on the 10th line and build/run the program then an exception will be thrown on the 11th line. However you'll get the following in the console window.
Unhandled Exception: System.Exception: Bangat LineDirective.Program.Main(String[] args) in C:\MyStuff\Code\C#\LineDirective\LineDirective\Program.cs:line 8
Interestingly here the file name is the correct filename and not the one we had passed. I'm not too sure on whether this is as expected or is a bug. I'll try to find this out.
Another interesting usage of #line directive is #line hidden. If you use this in a source file then all line information after this directive upto any other #line directive (other than another #line hidden) is skipped and not stored. Hence while stepping through code in the debugger these line will be skipped entirely.
In the following code
namespace LineDirective{ class Program { static void Main(string[] args) { foo(); }#line hidden static void foo() { Console.WriteLine("Bar"); }#line default }}
foo();
static void foo()
Console.WriteLine("Bar");
#line default
if you try to step into the function foo in the debugger you'll not be able to do so as the entire function definition is inside a #line hidden block and hence line number information for the whole function is missing in the pdb.
How does this work?
The .pdb file generated by the compiler contains line number information to allow the debugger to step through source code. In this for blocks of IL code the corresponding source file and line number information is stored. The #line directive makes the compiler change the line number information it puts into this file. There is an understanding between the debugger and the compiler that if the line number of a block of IL is set as 16707566 ( 0xFeeFee) then the debugger will simply step over this block of code. This is utilized in #line hidden and the compiler translates hidden to 0xFeeFee You can try out the following code to see this in action
using System;namespace LinePreProcDirective{ class Program { static void foo() { Console.WriteLine("foo");#line 16707566 Console.WriteLine("bar");#line default } static void Main(string[] args) { foo(); } }}
Console.WriteLine("foo");
Console.WriteLine("bar");
The code marked in bold will be skipped over if you try to step through this code in the debugger.
After using Ruby for some time I have become quiet attached to its conditional statement syntax. In particular I like statement modifiers which allow you to tag conditional statements at the end of a normal statement.
If C# supported this then in C# terms this'd mean instead of writing
if (!File.Exist(fileName)) throw new FileNotExistException(fileName));
if
You could have written
throw new FileNotExistException(fileName)) if (!File.Exist(fileName));
throw
If things go as it seems this could actually be the future of C#. I know this does not look that intuitive at first, but once I got used to it I started using it at all places. A quick glance in my Ruby sources reveals code like
Utility.showHelp if ARGV.length < 2 ARGV.each do |srcFileName| next if srcFileName =~ /^-/ #skip arguments starting with a - ... end
I liked the unless keyword as well. This is a negated version of if used in Ruby. If C# supported this then we could have written
unless (File.Exist(fileName)) throw new FileNotExistException(fileName));
or better still
throw new FileNotExistException(fileName) unless (File.Exist(fileName));
What I felt was not that intuitive is that in Ruby if is not a statment but is an expression similar to the ?: conditional expression in C/C++/C#. So for conditional assignment of values in Ruby you can write code as in
ageGroup = if age < 2 "Infant" elsif age < 19 "Teen" elsif age < 30 "Middle aged" else "old" end
In C# this'd become
string ageGroup; if (age < 2) ageGroup = "Infant"; else if (age < 19) ageGroup = "Teen"; else if (age < 30) ageGroup = "Middle aged"; else ageGroup = "old";
ageGroup =
The versioning scheme is 8.0.YMMDD.NN and that explains 8.0.50727. The mystery is with the build number .42. There are three top contenders for it, and no prize of guessing the correct one
Bangalore is famous world-over as the Indian version of Silicon city. I have never been to Silicon valley and so I'm not the right person to compare but a walk down some of the roads like the Airport road makes the comparison evident. Within a kilometer or two you'll see offices (or buildings) of Texas Instruments, Intel, ADI, IBM, Lucent, HP, Motorola, Microsoft, ADI on the side of the Road.
What makes Bangalore special is that most people living in the city are not natives of the place and have recently (<5years) moved in. Most of them are young and work in the Hi-Tech industry. I have never been to a city with so low average age of people and where you hear people arguing over the merits of J2EE on the side of the road and pub fight over C# and Java (yes its true :) ). We had some friends who were hardcore MS technology fans and some other who worked in Sun Microsystem :)
This unique environment along with institutes like IISc make Bangalore the geek city. Here are some reasons why
The final word is out!!! This is a great time indeed for most developers out there, Visual Studio 2005 has been released!!!!
I have been using Visual Studio for some time now, but all those years I was a customer of MS. This time I am in MS and in the DevTools team. Even though our product Visual Studio Team System is due next year I can hardly wait any longer. Its a proud moment for all of us here.