Such funding without funding than trying to what most free downloadable music free downloadable music online lending process i simple and completely? Where borrowers to triple digit interest will movies movies receive bad and addresses.

Home > Uncategorized > Instantiating Classes with Internal Constructors

Instantiating Classes with Internal Constructors

August 30th, 2009

broken-lock copy Scattered throughout the .NET framework are classes that are intended to appear externally sealed, but internally (by the framework class library developers) open for further extension. Because there is no mechanism to only allow classes to be sealed outside of the current assembly, framework developers at Microsoft use a compensating pattern: internal constructors.

Unfortunately, this has a side effect of making the classes uninstantiable. For the most part, this is not a problem as these classes are given to the developer already instantiated and ready to be consumed.

 

   1: public class DataReceivedEventArgs : EventArgs
   2: {
   3:     // Fields
   4:     internal string _data;
   5:  
   6:     // Methods
   7:     internal DataReceivedEventArgs(string data);
   8:  
   9:     // Properties
  10:     public string Data { get; }
  11: }
(System.Diagnostics.DataReceivedEventArgs as seen in Reflector. A good example of an example of internal constructor being used in the .NET framework FCL )

 

A practical example - What about mocking?

Mocking framework objects is the most common case where the internal constructor pattern causes an inconvenience. For the sake of example, image that you intend to test an event handler you just created that consumes DataReceivedEventArgs:

   1: private void NetErrorDataHandler(object SendingProcess, 
   2:     DataReceivedEventArgs ErrorLine)
   3: {
   4:     //Process New Error Data...
   5: }

 

You may try creating a unit test that passes in a custom DataReceivedEventArgs object with different data strings. Such as:

   1: DataReceivedEventArgs MockEventArgs = new DataReceivedEventArgs();

 

Unfortunately, you quickly realize that DataReceivedEventArgs can’t be instantiated:

compiler-error

(Actually a lie, DataReceivedEventArgs has a constructor defined but it’s just marked as “Internal”)

 

One plain solution to this problem would be to decouple your implementation of processing new error data from the event notification. Something like:

   1: private void NetErrorDataHandler(object SendingProcess, 
   2:     DataReceivedEventArgs ErrorLine)
   3: {
   4:     NetErrorData_Implementation(SendingProcess, ErrorLine.Data);
   5: }
   6:  
   7: private void NetErrorData_Implementation(object SendingProcess, 
   8:     string ErrorLineData) 
   9: {
  10:     //Process New Error Data...
  11: }

 

Now, you can test the implementation freely. This is a completely valid way to sidestep the uninstantiable object issue with testing.

Of course, you’ve just paid for your new ability with an entirely new method and a minimum of four new lines of code to maintain. Following this pattern with many events could add up to a significant maintenance cost down the road.

 

Instantiating the Uninstantiable

An alternative to changing your implementation is to use a mixture of reflection and serialization helper methods to create your target object without calling any constructors, and then manually set its private/internal fields.

Yes, you heard me correctly, create an object without calling any constructors.

This is not only possible, but easy (about one line of code in c#), believe it or not! Simply call GetUninitializedObject. Let me show you an example:

 

   1: DataReceivedEventArgs MockEventArgs =
   2:     (DataReceivedEventArgs)System.Runtime.Serialization.FormatterServices
   3:      .GetUninitializedObject(typeof(DataReceivedEventArgs));

(Creates a new DataReceivedEventArgs object called MockEventArgs)

 

zombie_object At this point in execution, the zombie object will leap to life, with no soul (or state for that matter).

The first thing you should be concerned about is plugging in some values for the private fields, which will be null and performing any critical rolls the constructor would have.

I strongly recommend studying the constructor of your target object in a tool such as Reflector, before initializing it yourself.

Here’s an example of setting the (single) internal field on MockEventArgs:

 

   1: FieldInfo[] EventFields = typeof(DataReceivedEventArgs)
   2:     .GetFields(
   3:         BindingFlags.NonPublic |
   4:         BindingFlags.Instance |
   5:         BindingFlags.DeclaredOnly);
   6:  
   7: if (EventFields.Count() > 0)
   8: {
   9:     EventFields[0].SetValue(MockEventArgs, “This is dynamically a injected value” );
  10: }
  11: else
  12: {
  13:     throw new ApplicationException(
  14:         "Failed to find any fields!");
  15: }

That’s it! Now the MockEventArgs object can be used just as if it came from inside the framework and your test method can emulate the event:

   1: NetErrorDataHandler(new Object(), MockEventArgs);

 

Making it Reusable

Obviously typing out this code every time you needed to mock up an uninstantiable object would be a major headache. I packaged these into a neat set of methods that makes it easy to mock up these difficult objects in only a few lines of code. Here’s the finished product:

(Updated on August 31st)

Download RMock.cs

   1:         /// <summary>
   2:         /// Instantiates T without calling a constructor.
   3:         /// Works well with otherwise uninstantiable objects.
   4:         /// </summary>
   5:         /// <typeparam name="T">Anything that does NOT derive
   6:         /// from ContextBoundObject.</typeparam>
   7:         /// <param name="Values">A dictionary of values to initialize
   8:         /// the object in place of a constructor.</param>
   9:         /// <returns>The newly created and instantiated object.</returns>
  10:         public static T Create<T>(Dictionary<string, object> Values)
  11:         {
  12:  
  13:             if (Values == null)
  14:                 throw new ArgumentNullException("Values", "Values is null.");
  15:  
  16:             return Fill<T>(
  17:                 CreateBlank<T>(),
  18:                 Values);
  19:  
  20:         }
  21:  
  22:         private static T CreateBlank<T>()
  23:         {
  24:  
  25:             if (typeof(ContextBoundObject).IsAssignableFrom(typeof(T)) == true)
  26:             {
  27:                 throw new ApplicationException(
  28:                     "You can't use types that derive from ContextBoundObject.");
  29:             }
  30:  
  31:             return (T)System.Runtime.Serialization.FormatterServices
  32:                  .GetUninitializedObject(typeof(T));
  33:         }
  34:  
  35:  
  36:         private static T Fill<T>(T Source, Dictionary<string, object> Values)
  37:         {
  38:             if (Source == null)
  39:                 throw new ArgumentNullException("Source", "Source is null.");
  40:  
  41:             if (Values == null)
  42:                 throw new ArgumentNullException("Values", "Values is null");
  43:  
  44:             if (Values.Count == 0)
  45:                 return Source;
  46:  
  47:             FieldInfo[] EventFields = typeof(T)
  48:                 .GetFields(
  49:                     BindingFlags.NonPublic |
  50:                     BindingFlags.Public |
  51:                     BindingFlags.Instance |
  52:                     BindingFlags.DeclaredOnly);
  53:  
  54:             if (EventFields != null && EventFields.Count() > 0)
  55:             {
  56:                 foreach (FieldInfo Field in EventFields)
  57:                 {
  58:                     if (Values.ContainsKey(Field.Name) == true
  59:                         && Field.FieldType
  60:                             .IsAssignableFrom(Values[Field.Name]
  61:                                 .GetType()) == true)
  62:                     {
  63:                         Field.SetValue(Source, Values[Field.Name]);
  64:                     }
  65:                 }
  66:             }
  67:  
  68:             return Source;
  69:  
  70:         }

Example Usage:

   1: var Values = new Dictionary<string, object>()
   2:     {
   3:         {"_data","This is an injected string"}
   4:     };
   5:  
   6: DataReceivedEventArgs MockEventArgs
   7:     = RMock.MockServices.Create<DataReceivedEventArgs>(Values);

Share/Save/Bookmark

Robert Uncategorized

  1. syntatic
    August 30th, 2009 at 21:11 | #1

    Looks like you forgot to genericize part of RMock.cs. It should use the generic on line 47.

    Instead of this:
    47: FieldInfo[] EventFields = typeof(DataReceivedEventArgs)

    It should be this:
    47: FieldInfo[] EventFields = typeof(T)

  2. August 31st, 2009 at 06:30 | #2

    Thank you, fixed (with one other bug)

  3. September 16th, 2009 at 18:57 | #3

    This is freakin awesome! Crazy that we have to do this crap, but awesome! :D

  4. Mark
    January 25th, 2010 at 09:50 | #4

    This is absolutely awesome

  5. Matt
    February 22nd, 2010 at 09:08 | #5

    This is exactly what I needed. Thanks!

  6. kamalt
    April 6th, 2010 at 20:10 | #6

    Is there a way to make a class with internal constructor as Serializable?

  7. April 9th, 2010 at 23:03 | #7

    Classes with internal constructors are xml serializable out of the box, but the constructors need to be parameterless. Unfortunately, there is no easy way xml serialize an object with a private or internal parameterized constructor. If this was critically important you could probably hack together your own serialization engine to cope by using GetUninitializedObject and a lot of reflection.

  1. August 30th, 2009 at 20:05 | #1
  2. August 30th, 2009 at 22:01 | #2
  3. March 12th, 2014 at 00:09 | #3