Click here to Skip to main content
15,881,139 members

The Weird and The Wonderful

   

The Weird and The Wonderful forum is a place to post Coding Horrors, Worst Practices, and the occasional flash of brilliance.

We all come across code that simply boggles the mind. Lazy kludges, embarrassing mistakes, horrid workarounds and developers just not quite getting it. And then somedays we come across - or write - the truly sublime.

Post your Best, your worst, and your most interesting. But please - no programming questions . This forum is purely for amusement and discussions on code snippets. All actual programming questions will be removed.

 
GeneralRe: .Net Core 6 jumps the shark Pin
MSBassSinger29-Nov-21 4:25
professionalMSBassSinger29-Nov-21 4:25 
GeneralRe: .Net Core 6 jumps the shark Pin
Jon McKee4-Dec-21 13:37
professionalJon McKee4-Dec-21 13:37 
GeneralRe: .Net Core 6 jumps the shark Pin
MSBassSinger4-Dec-21 13:56
professionalMSBassSinger4-Dec-21 13:56 
GeneralRe: .Net Core 6 jumps the shark Pin
Jon McKee4-Dec-21 14:21
professionalJon McKee4-Dec-21 14:21 
GeneralRe: .Net Core 6 jumps the shark Pin
MSBassSinger4-Dec-21 15:00
professionalMSBassSinger4-Dec-21 15:00 
GeneralRe: .Net Core 6 jumps the shark Pin
Jon McKee4-Dec-21 16:12
professionalJon McKee4-Dec-21 16:12 
GeneralRe: .Net Core 6 jumps the shark Pin
Richard Deeming5-Dec-21 22:00
mveRichard Deeming5-Dec-21 22:00 
GeneralRe: .Net Core 6 jumps the shark Pin
MSBassSinger7-Dec-21 8:53
professionalMSBassSinger7-Dec-21 8:53 
Quote:
Code written with a using block is going to be significantly more "correct" than code that eschews it in favour of manual clean-up.


That comes across as more religion than a rational approach.

In order to illustrate my point, I can add the C# code I used for the test (in .NET 6.0) and the MSIL output of both. The unit test for the "using" statement took 28 ms, while the standard use took 18 ms. The MSIL for the "using" statement produced 47 lines of MSIL code, while the standard approach without "using" produced 31 lines of MSIL code.

I kept the IDisposable instance simple for this example.

In order to capture the constructor exception, the using block has to be wrapped with a try-catch.

The results of this test, combined with how I capture exception data and the runtime values associated with the exception (to significantly reduce support costs of the SDLC), is why I do not use the "using" statement in production apps. I do use it where appropriate in proof-of-concept and personal utilities, where support and performance is less of a concern.

IDisposable class:
namespace UsingTest
{
	public class DisposableClass : IDisposable
	{

		private Boolean m_blnDisposeHasBeenCalled = false;

		public DisposableClass()
		{
			Int32 denom = 20;
			Int32 numer = 0;
			Int32 result = denom / numer;

		}

		public String WhoIsIt()
		{
			return $"{Environment.UserDomainName}\\{Environment.UserName} on {Environment.MachineName} from {Environment.CurrentDirectory} on thread ID {Environment.CurrentManagedThreadId.ToString()}.";
		}

		#region IDisposable Implementation

		/// <summary>
		/// Implement the IDisposable.Dispose() method
		/// Developers are supposed to call this method when done with this Object.
		/// There is no guarantee when or if the GC will call it, so 
		/// the developer is responsible to.  GC does NOT clean up unmanaged 
		/// resources, such as COM objects, so we have to clean those up, too.
		/// 
		/// </summary>
		public void Dispose()
		{
			try
			{
				// Check if Dispose has already been called 
				// Only allow the consumer to call it once with effect.
				if (!m_blnDisposeHasBeenCalled)
				{
					// Call the overridden Dispose method that contains common cleanup code
					// Pass true to indicate that it is called from Dispose
					Dispose(true);

					// Prevent subsequent finalization of this Object. This is not needed 
					// because managed and unmanaged resources have been explicitly released
					GC.SuppressFinalize(this);
				}
			}
			catch (Exception exUnhandled)
			{
				exUnhandled.Data.Add("m_blnDisposeHasBeenCalled", m_blnDisposeHasBeenCalled.ToString());
				throw;
			}
		}

		/// <summary>
		/// Explicit Finalize method.  The GC calls Finalize, if it is called.
		/// There are times when the GC will fail to call Finalize, which is why it is up to 
		/// the developer to call Dispose() from the consumer Object.
		/// </summary>
		~DisposableClass()
		{
			// Call Dispose indicating that this is not coming from the public
			// dispose method.
			Dispose(false);
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		public void Dispose(Boolean disposing)
		{
			try
			{
				// Here we dispose and clean up the unmanaged objects and managed Object we created in code
				// that are not in the IContainer child Object of this object.
				// Unmanaged objects do not have a Dispose() method, so we just set them to null
				// to release the reference.  For managed objects, we call their respective Dispose()
				// methods and then release the reference.
				// DEVELOPER NOTE:
				//if (m_obj != null)
				//    {
				//    m_obj = null;
				//    }

				// Set the flag that Dispose has been called and executed.
				m_blnDisposeHasBeenCalled = true;
			}
			catch (Exception exUnhandled)
			{
				exUnhandled.Data.Add("m_blnDisposeHasBeenCalled", m_blnDisposeHasBeenCalled.ToString());
				throw;
			}
		}
		#endregion IDisposable Implementation
	}
}


Unit test with the "using" statement
[TestMethod]
public void UsingStatementTest()
{
    try
    {
        using (DisposableClass test = new())
        {
            try
            {
                String result = test.WhoIsIt();
            }
            catch (Exception ex)
            {
                Assert.Fail($"INNER: {ex.Message}");
            }
        }
    }
    catch (Exception exOuter)
    {
        Assert.Fail($"OUTER: {exOuter.Message}");
    }
}


Unit test with a standard approach:
[TestMethod]
public void StandardUsageTest()
{

    DisposableClass test = null;

    try
    {
        test = new();

        String result = test.WhoIsIt();
    }
    catch (Exception exOuter)
    {
        Assert.Fail($"ONLY: {exOuter.Message}");
    }
    finally
    {
        test?.Dispose();
    }
}


MSIL from the "using" statement text method:
.try
{
  IL_0000:  newobj     instance void [UsingTest]UsingTest.DisposableClass::.ctor()
  IL_0005:  stloc.0
  .try
  {
    .try
    {
      IL_0006:  ldloc.0
      IL_0007:  callvirt   instance string [UsingTest]UsingTest.DisposableClass::WhoIsIt()
      IL_000c:  pop
      IL_000d:  leave.s    IL_0027
    }  // end .try
    catch [System.Runtime]System.Exception
    {
      IL_000f:  stloc.1
      IL_0010:  ldstr      "INNER: "
      IL_0015:  ldloc.1
      IL_0016:  callvirt   instance string [System.Runtime]System.Exception::get_Message()
      IL_001b:  call       string [System.Runtime]System.String::Concat(string,
                                                                        string)
      IL_0020:  call       void [Microsoft.VisualStudio.TestPlatform.TestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.Assert::Fail(string)
      IL_0025:  leave.s    IL_0027
    }  // end handler
    IL_0027:  leave.s    IL_0033
  }  // end .try
  finally
  {
    IL_0029:  ldloc.0
    IL_002a:  brfalse.s  IL_0032
    IL_002c:  ldloc.0
    IL_002d:  callvirt   instance void [System.Runtime]System.IDisposable::Dispose()
    IL_0032:  endfinally
  }  // end handler
  IL_0033:  leave.s    IL_004d
}  // end .try
catch [System.Runtime]System.Exception
{
  IL_0035:  stloc.2
  IL_0036:  ldstr      "OUTER: "
  IL_003b:  ldloc.2
  IL_003c:  callvirt   instance string [System.Runtime]System.Exception::get_Message()
  IL_0041:  call       string [System.Runtime]System.String::Concat(string,
                                                                    string)
  IL_0046:  call       void [Microsoft.VisualStudio.TestPlatform.TestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.Assert::Fail(string)
  IL_004b:  leave.s    IL_004d
}  // end handler


MSIL for the unit test of the standard approach:
.try
{
  .try
  {
    IL_0002:  newobj     instance void [UsingTest]UsingTest.DisposableClass::.ctor()
    IL_0007:  stloc.0
    IL_0008:  ldloc.0
    IL_0009:  callvirt   instance string [UsingTest]UsingTest.DisposableClass::WhoIsIt()
    IL_000e:  pop
    IL_000f:  leave.s    IL_0033
  }  // end .try
  catch [System.Runtime]System.Exception
  {
    IL_0011:  stloc.1
    IL_0012:  ldstr      "ONLY: "
    IL_0017:  ldloc.1
    IL_0018:  callvirt   instance string [System.Runtime]System.Exception::get_Message()
    IL_001d:  call       string [System.Runtime]System.String::Concat(string,
                                                                      string)
    IL_0022:  call       void [Microsoft.VisualStudio.TestPlatform.TestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.Assert::Fail(string)
    IL_0027:  leave.s    IL_0033
  }  // end handler
}  // end .try
finally
{
  IL_0029:  ldloc.0
  IL_002a:  brfalse.s  IL_0032
  IL_002c:  ldloc.0
  IL_002d:  call       instance void [UsingTest]UsingTest.DisposableClass::Dispose()
  IL_0032:  endfinally
}  // end handler

GeneralRe: .Net Core 6 jumps the shark Pin
Richard Deeming7-Dec-21 22:10
mveRichard Deeming7-Dec-21 22:10 
GeneralRe: .Net Core 6 jumps the shark Pin
MSBassSinger8-Dec-21 5:17
professionalMSBassSinger8-Dec-21 5:17 
GeneralRe: .Net Core 6 jumps the shark Pin
Richard Deeming8-Dec-21 6:18
mveRichard Deeming8-Dec-21 6:18 
GeneralRe: .Net Core 6 jumps the shark Pin
PIEBALDconsult11-Dec-21 8:50
mvePIEBALDconsult11-Dec-21 8:50 
GeneralRe: .Net Core 6 jumps the shark Pin
zezba900029-Nov-21 9:35
zezba900029-Nov-21 9:35 
GeneralRe: .Net Core 6 jumps the shark Pin
PIEBALDconsult11-Dec-21 8:42
mvePIEBALDconsult11-Dec-21 8:42 
GeneralWhat the heck are they teaching philosophers in Florida? Pin
honey the codewitch28-Nov-21 5:54
mvahoney the codewitch28-Nov-21 5:54 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
trønderen28-Nov-21 6:04
trønderen28-Nov-21 6:04 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
honey the codewitch28-Nov-21 6:05
mvahoney the codewitch28-Nov-21 6:05 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
honey the codewitch28-Nov-21 6:08
mvahoney the codewitch28-Nov-21 6:08 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
Daniel Pfeffer28-Nov-21 21:37
professionalDaniel Pfeffer28-Nov-21 21:37 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
Greg Utas28-Nov-21 6:06
professionalGreg Utas28-Nov-21 6:06 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
honey the codewitch28-Nov-21 6:06
mvahoney the codewitch28-Nov-21 6:06 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
Greg Utas28-Nov-21 6:49
professionalGreg Utas28-Nov-21 6:49 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
honey the codewitch28-Nov-21 6:50
mvahoney the codewitch28-Nov-21 6:50 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
Greg Utas28-Nov-21 6:53
professionalGreg Utas28-Nov-21 6:53 
GeneralRe: What the heck are they teaching philosophers in Florida? Pin
Marc Clifton28-Nov-21 7:01
mvaMarc Clifton28-Nov-21 7:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.