Often, in exception handling, we would need to re-throw an exception caught in the catch block, after doing some operation (logging the exception, for instance). But, we generally make the mistake of providing the exception argument in the throw expression. The problem is that, in this case, we might lose the original call stack. Here's a small snippet to give you the idea:
static void exA()
{
try
{
exB();
}
catch(Exception ex)
{
//Watch out!
//throw ex;
//Better
throw;
}
}
static void exB()
{
throw new Exception("New Exception");
}
static void Main(string[] args)
{
try
{
exA();
}
catch(Exception e)
{
Console.WriteLine(e.StackTrace);
}
}
If we were to do a throw ex in the above snippet, then we would have the following stacktrace. Note that we have lost exB() in the stack trace.
exA()
Main(String[] args)
If we were to just re-throw the exception, then we would have got the entire stack trace
exB()
exA()
Main(String[] args)
For more information refer to the C# Language Specification and Lance Hunt's C# Coding Guidelines for .NET.
It is more than a common requirement to be able to start another process from executing code. For instance, you might want to execute a batch file, run a command line utility of sorts, and so on. This is facilitated in the BCL through System.Diagnostics.Process class, more specifically, the Start method.
Process.Start("Notepad.exe");
You can also specify startup information like FileName, Argument, WindowStyle and so on, through the instance of another class called ProcessStartInfo.
ProcessStartInfo oStartInfo = new ProcessStartInfo();
oStartInfo.FileName = "Notepad.exe";
oStartInfo.Arguments = "MyWork.txt";
Process.Start(oStartInfo);
Simple. But there is a catch here. The instance of ProcessInfo bears a property called UseShellExecute. A value of true for this property would mean that the windows shell is used to start a process, and this is the default value. Therefore, you wouldn’t be able to extract the output or provide an alternative input for the process to be executed. This feature would be required, for instance, if you want to capture the output of a SQL script execution through osql.exe or as another example, the output of a command-line setup. So, to make this work, we need to set UseShellExecute to false and then, as required, set RedirectStandardInput (default is keyboard), RedirectStandardOutput (default is monitor), RedirectStandardError (default is monitor) properties to true. One thing to keep in mind, in this case is that, you should specifiy the full path of the executable or the path must be listed in the PATH environment variable. The code snippet given below captures the execution of a batch file and writes it to a log file:
Process runCmd = new Process();
runCmd.StartInfo.FileName = "RunBatch.bat";
runCmd.StartInfo.UseShellExecute = false;
runCmd.StartInfo.RedirectStandardOutput = true;
runCmd.Start();
FileStream fs = new FileStream("OutPut.log",FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.Write(runCmd.StandardOutput.ReadToEnd());
runCmd.WaitForExit();
sw.Close();
fs.Close();
Another simple tip is that, when UseShellExecute is true, you can start any document if its file type is associated with an executable that has the default action as open. For e.g. The following code launches test.txt in default text editor (notepad on my m/c)
ProcessStartInfo psi= new ProcessStartInfo(@"C:\test.txt");
Process.Start(psi);
You can say also associate verbs like Print etc.
ProcessStartInfo psi= new ProcessStartInfo(@"C:\test.txt");
psi.verb = "Print";
Process.Start(psi);
As another example, the following code launches the URL provided in the default browser.
Process.Start("http://www.microsoft.com");
Many a times in your application, you would want to have a security scheme which would ensure that your code is not referenced and misused by other assemblies. For instance, there might be public types representing custom Identities and Principals which you wouldn’t want other applications to use, or some sensitive/proprietary logic, you name it. .NET BCL does provide a handy class StrongNameIdentityPermission which gives you a simple scheme for effecting the same.
You can refer to this walkthrough for more information on how this permission can be used. Also, check this blog entry and the related discussion for more insights.
We all know that types, including interfaces can have a default property. Default properties are used as a short-hand notation for accessing items in an array/collection of objects contained within the object. For e.g. Item is the default property of an ArrayList (for that matter, IList.Item) which gets the object stored in the specified index. For eg :
Dim arrItems As New ArrayList
Console.WriteLine(CType(arrItems(0), String))
'Equivalent to this
'Console.WriteLine(CType(arrItems.Item(0), String))
In C#, default properties are called Indexers. There is a subtle difference in the way indexers are declared in VB.NET and C#. Here's an example (MSDN):
' Visual Basic
' A class that contains many Widgets
Public Class Widgets
'Default property implementation
Default Public Property Widget(ByVal I As Integer) As Widget
Get
' Implementation code to return a widget goes here.
End Get
Set(ByVal Value As Widget)
' Implementation code to set a widget goes here.
End Set
End Property
End Class
// C#
// Class that contains many Widgets.
public class Widgets
{
// Indexer implementation.
public Widget this[int index]
{
get
{
// Insert code to return a Widget.
}
set
{
// Insert code to set a Widget.
}
}
}
If you notice, there is no provision to specify the name of the Indexer in C#, as present in VB.NET. In C#, the name defaults to "Item". However, you can specify a name by means of an attribute as shown below:
[System.Runtime.CompilerServices.CSharp.IndexerName("Widget")]
public int this [int index] { }
Here are some other aspects of an Indexer we need to know:
1. You can have only one Default property/Indexer per class. The Indexer, however, can be overloaded.
2. Default properties should accept parameters. We cannot have VB6 like (parameterless) properties. Refer to this link
for Property changes in VB.NET as compared to VB.
Finally, a tip to end this note on indexers; a frequently asked question in the newsgroups. If we need to find out programmatically, if a class has an indexer, we can query a custom attribute called DefaultMemberAttribute attribute using Reflection as shown below:
static bool CheckIfIndexerPresent(Object obj)
{
object[] oAttributes = obj.GetType().GetCustomAttributes(true);
for(short j = 0; j < oAttributes.Length; j++)
{
if (oAttributes[j] is DefaultMemberAttribute)
{
return true;
}
}
return false;
}
Often, it may be necessary to inspect whether a particular assembly was compiled with a Debug configuration (or Release configuration). For instance, you might want to run a tool of sorts on a build folder to ensure that all assemblies are compiled in the Release configuration. The reason being that - in Debug mode, certain JIT optimizations are turned off (to aid debugging) and you would want them to be turned on for the production environment.
We can inspect this by checking for an attribute DebuggableAttribute (System.Diagnostics namespace) in the assembly metadata. The compiler would automatically qualify the assembly/module with this attribute when compiled in the debug configuration. All we need to do is use Reflection to extract this information out. Given below is a C# code snippet for the same [Courtesy: Nick Weinholt (MVP), News Groups]:
static bool IsDebugMode(Assembly objAssembly)
{
object[] atts = objAssembly.GetCustomAttributes(typeof(DebuggableAttribute), true);
if (atts.Length == 0)
{
Console.WriteLine("This is a Release Configuration");
return false;
}
DebuggableAttribute da = atts[0] as DebuggableAttribute;
if (da != null)
{
bool standardDebugBuild = da.IsJITOptimizerDisabled && da.IsJITTrackingEnabled;
Console.WriteLine("Standard DebugBuild = {0}", standardDebugBuild);
return true;
}
return false;
}