|
|
Using your Environment | | .NET's Environment Class has a whole host of features that you will probably want to take advantage of at some point in your programming if you haven't done so already. Below is simple a code snippet and above each line, a description of what it does. This namespace is very easy to use and gives you a lot of out of the box functionality. What I'd like to do is show you how it works from the code side, and then examine what's happening in the disassembly. As you'll see, this class mimicks the actual IL instructions very closely and is very efficient to use. Also, note that all of the properties and methods are static/shared so you don't need to instantiate an instance of the Environment object to use it. That allows you to write less code and makes it very easy to use.
//5.0.2195.0
Debug.WriteLine(Environment.OSVersion.Version);
//SomeDomainName
Debug.WriteLine(Environment.UserDomainName);
//WR-Primary
Debug.WriteLine(Environment.MachineName);
//wryan
Debug.WriteLine(Environment.UserName);
//C:\RatesManager\bin\Debug
Debug.WriteLine(Environment.CurrentDirectory);
//491509031
Debug.WriteLine(Environment.TickCount.ToString());
//1.1.4322.573 - Shows that the Autobuild is working
Debug.WriteLine(Environment.Version.ToString());
//This is the '.NET' way to insert a new line or carriage return
//Using this method, you add a new line based on the operating system
//version. So when .NET is implemented on different operating systems,
//you won't have to rework your code to accomodate differences between
//Unix, Linux, Windows, MAC etc
Debug.WriteLine(Environment.NewLine);
//20746240
Debug.WriteLine(Environment.WorkingSet.ToString());
//And Remember, this is the first call of the program!
//at System.Environment.GetStackTrace(Exception e)
//at System.Environment.GetStackTrace(Exception e)
//at System.Environment.get_StackTrace()
//at RatesManager.Utility..ctor() in c:\ratesmanager\utility.cs:line 31
//at RatesManager.Form1.Form1_Load(Object sender, EventArgs e) in c:\ratesmanager\form1.cs:line 325
//at System.Windows.Forms.Form.OnLoad(EventArgs e)
//at System.Windows.Forms.Form.OnCreateControl()
//at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
//at System.Windows.Forms.Control.CreateControl()
//at System.Windows.Forms.Control.WmShowWindow(Message& m)
//at System.Windows.Forms.Control.WndProc(Message& m)
//at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
//at System.Windows.Forms.ContainerControl.WndProc(Message& m)
//at System.Windows.Forms.Form.WmShowWindow(Message& m)
//at System.Windows.Forms.Form.WndProc(Message& m)
//at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
//at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
//at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
//at System.Windows.Forms.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow)
//at System.Windows.Forms.Control.SetVisibleCore(Boolean value)
//at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
//at System.Windows.Forms.Control.set_Visible(Boolean value)
//at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
//at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
//at System.Windows.Forms.Application.Run(Form mainForm)
//at RatesManager.Form1.Main() in c:\ratesmanager\form1.cs:line 321
Debug.WriteLine(Environment.StackTrace.ToString()); |
At this point, you should notice a few things. Right off the bat the Environment knows quite a bit about who you are and where you are doing it from. This, combined with some Code Access Security can give you some real flexibility in making secure and responsive applications. Since this is one of the easiest classes to use, I think the above code is pretty much self explanatory. However, I think it's important to understand what's going on behind the scenes. So what does the disassembly look like?
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 138 (0x8a)
.maxstack 2
.locals init ([0] int32 CS$00000002$00000000,
[1] int64 CS$00000002$00000001)
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: call class [mscorlib]System.OperatingSystem [mscorlib]System.Environment::get_OSVersion()
IL_000b: callvirt instance class [mscorlib]System.Version [mscorlib]System.OperatingSystem::get_Version()
IL_0010: call void [System]System.Diagnostics.Debug::WriteLine(object)
IL_0015: call string [mscorlib]System.Environment::get_UserDomainName()
IL_001a: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_001f: call string [mscorlib]System.Environment::get_MachineName()
IL_0024: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0029: call string [mscorlib]System.Environment::get_UserName()
IL_002e: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0033: call string [mscorlib]System.Environment::get_CurrentDirectory()
IL_0038: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_003d: call int32 [mscorlib]System.Environment::get_TickCount()
IL_0042: stloc.0
IL_0043: ldloca.s CS$00000002$00000000
IL_0045: call instance string [mscorlib]System.Int32::ToString()
IL_004a: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_004f: call class [mscorlib]System.Version [mscorlib]System.Environment::get_Version()
IL_0054: callvirt instance string [mscorlib]System.Version::ToString()
IL_0059: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_005e: call string [mscorlib]System.Environment::get_NewLine()
IL_0063: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0068: call int64 [mscorlib]System.Environment::get_WorkingSet()
IL_006d: stloc.1
IL_006e: ldloca.s CS$00000002$00000001
IL_0070: call instance string [mscorlib]System.Int64::ToString()
IL_0075: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_007a: call string [mscorlib]System.Environment::get_StackTrace()
IL_007f: callvirt instance string [mscorlib]System.String::ToString()
IL_0084: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0089: ret
} // end of method Utility::.ctor |
If you examine the disassembly, it's pretty evident what's happening behind the scenes, and it's very simple. You can see that unlike some other features of .NET the disassembly instructions mimick the C# code almost verbatim. This shows you that there isn't a high layer of abstraction between the IL and the code in your language of choice. You will also invariably see what happens when you call Debug.WriteLine...namely it's a void function that passes in a string argument. This is pretty much what you would expect...that's why everything that isn't a string needs converted to a string before you pass it into Debug.WriteLine in C#, and in VB.NET, the same must occur if you have on Option Strict. If you don't (you deserve all the associated evil with leaving it off) you can easily see by the IL what has to happen. The function has to take in a string...so the CLR has to do this for you. This has to happen at runtime, which makes it late bound...slowing down everything and forcing the runtime to guess what your intention is as opposed to knowing it explicitly. I suspect if more folks looked at the disassembled versions of their code, they wouldn't be so quick to defend some of their bad habits.
I'd like to point out another thing. Look at instruction IL_0054:. You'll see that it appends a ToString() call at the end of it. Since Version already returns a string in the first place, adding a ToString() is unnecessary and causes extra effort to be exerted to do the exact same thing. I did this on purpose to show why knowing what's happening under the hood is so important. If you don't, you may end up writing many other things like the one above that compiles, seems to work fine, but has built in inefficiency.
|
|