In this article I will write about my top 10 tips in C# programming. Each tip will be supported by the sample C# codes, which will make it easy for the C# newbies to get a hold on.
Tip 1: Write Unit Test Cases for Non-Public Methods
Have you ever tried writing unit test cases for methods of an assembly which are not public? Most developers don’t because they are not visible to the test project. C# allows you to make the assembly internals visible to other assemblies. Adding the attribute shown below in the AssemblyInfo.cs file does the trick.
//Make the internals visible to the test assembly [assembly: InternalsVisibleTo("MyTestAssembly")]
Tip 2: Use Tuples
I have seen developers creating a POCO class just for the sake of returning multiple values from a method. Tuples are introduced in .NET Framework 4.0 which can be used effectively as shown below.
public Tuple<int, string, string> GetEmployee() { int employeeId = 1001; string firstName = "Rudy"; string lastName = "Koertson"; //Create a tuple and return return Tuple.Create(employeeId, firstName, lastName); }
Tip 3: No Need for Temporary Collections, Yield Might Help
Normally when we need to fetch the items from a collection we might create a temporary list to hold the retrieved items and return. Following is the C# code using the temporary list.
public List<int> GetValuesGreaterThan100(List<int> masterCollection) { List<int> tempResult = new List<int>(); foreach (var value in masterCollection) { if (value > 100) tempResult.Add(value); } return tempResult; }
To avoid the usage of this temporary collection you could choose to use the yield. It will yield the result as and when the result set is enumerated. Below is the code using the yield keyword.
public IEnumerable<int> GetValuesGreaterThan100(List<int> masterCollection) { foreach (var value in masterCollection) { if (value > 100) yield return value; } }
Of course you could also use LINQ.
Tip 4: Telling the World that you are Retiring a Method Soon
In case you own a re-distributable component and you are planning to deprecate a method soon, then you can decorate the method with the obsolete attribute to communicate it to the clients. Here is the sample C# code.
[Obsolete("This method will be deprecated soon. You could use XYZ alternatively.")] public void MyComponentLegacyMethod() { //Here is the implementation }
The client applications will get a warning with the given message upon compilation. Incase if you want to fail the client build if they are using the deprecated method then pass the extra Boolean parameter as True.
[Obsolete("This method is deprecated. You could use XYZ alternatively.", true)] public void MyComponentLegacyMethod() { //Here is the implementation }
Tip 5: Remember Deferred Execution While Writing LINQ Queries
In .NET when you write a LINQ query it actually performs the querying only when the LINQ result is accessed. This phenomenon of LINQ is called deferred execution. One thing you should be aware of is that on every access of the result set the query gets executed again and again.
To avoid the repeated execution convert the LINQ result to List upon execution as shown below.
public void MyComponentLegacyMethod(List<int> masterCollection) { //Without the ToList this linq query will be executed twice because of the following usage var result = masterCollection.Where(i => i > 100).ToList(); Console.WriteLine(result.Count()); Console.WriteLine(result.Average()); }
Tip 6: Converting Business Entities Using Explicit Keyword
Use the explicit keyword to define the conversion of one business entity to another. The conversion method will be invoked when the conversion is requested in code. Here is the sample conversion code.
class Program { static void Main(string[] args) { ExternalEntity entity = new ExternalEntity() { Id = 1001, FirstName = "Dave", LastName = "Johnson" }; MyEntity convertedEntity = (MyEntity)entity; } } class MyEntity { public int Id { get; set; } public string FullName { get; set; } public static explicit operator MyEntity(ExternalEntity externalEntity) { return new MyEntity() { Id = externalEntity.Id, FullName = externalEntity.FirstName + " " + externalEntity.LastName }; } } class ExternalEntity { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
Tip 7: Retaining the Exact Stack Trace
In a C# program in the catch block if you throw the exception as given below and the error has occurred in the method ConnectDatabase, the thrown exception stack trace will only show that the error has occurred in the RunDataOperation method. It would have lost the actual error source.
public void RunDataOperation() { try { Intialize(); ConnectDatabase(); Execute(); } catch (Exception exception) { throw exception; } }
To retain the actual stack trace throw as shown below.
public void RunDataOperation() { try { Intialize(); ConnectDatabase(); Execute(); } catch (Exception) { throw; } }
Tip 8: Flags Attribute – Enum Grouping
Decorating the enum with the Flags attribute in C# will enable the enum as bit fields. This allows us to group the enum values. Here is a sample piece of C# code.
class Program { static void Main(string[] args) { int snakes = 14; Console.WriteLine((Reptile)snakes); } } [Flags] enum Reptile { BlackMamba = 2, CottonMouth = 4, Wiper = 8, Crocodile = 16, Aligator = 32 }
The output for the above code will be “BlackMamba, CottonMouth, Wiper”. If the flags attribute is removed then the output will be 14 as it is.
Tip 9: Enforcing the Base Type for a Generic Type
Let’s say you created a generic class and you need to enforce that the generic type provided in the class should inherit from a specific interface, then you could do it as shown in the below sample.
class MyGenricClasswhere T : IMyInterface { //Body of the class come in here }
You could also do it at the method level.
class MyGenricClass { public void MyGenericMethod(T t) where T : IMyInterface { //Generic implementation goes in here } }
Tip 10: Exposing Property as IEnumerable Doesn’t Mean It’s Readonly
In a class that you have created, if an IEnumerable property is exposed the callers can still be able to modify them as shown.
class Program { static void Main(string[] args) { MyClass myClass = new MyClass(); ((List<string>)myClass.ReadOnlyNameCollection).Add("######From Client#####"); myClass.Print(); } } class MyClass { List<string> _nameCollection = new List<string>(); public MyClass() { _nameCollection.Add("Rob"); _nameCollection.Add("John"); _nameCollection.Add("Jummy"); _nameCollection.Add("Derek"); } public IEnumerable<string> ReadOnlyNameCollection { get { return _nameCollection.AsEnumerable(); } } public void Print() { foreach (var item in ReadOnlyNameCollection) { Console.WriteLine(item); } } }
The code does successfully modify the list and adds a new name. One way to avoid this is to add AsReadOnly instead of AsEnumerable.
public IEnumerable<string> ReadOnlyNameCollection { get { return _nameCollection.AsReadOnly(); } }
I hope this article was informative though you might be aware of few things already. Happy reading!