Posts Tagged Reflection

C#: ToString To Report all Properties Even Private Ones Via Reflection

At some point one needs to view all the properties of an instance outside of a debugger such as for a unit test reporting the results or possibly a console application informing its status to the output. To achieve the results one overrides ToString() and by hand writes the information of the instance’s properties and their values to the output string. This can become cumbersome if the class instance is changing or when one realizes that the time ratio of creating such a reporting operation verses the size of what is being reported can lead to valuable time taken away from the developer.

This article demonstrates a C# extension which will take any class instance and report any non null properties as well as any string lists. The goal of the report is to provide information on the standard properties (string, int, datetime, etc) as well as string lists and ignores any  complex objects. Also provided is the ability to show the non-public properties.

For the resulting visual list, the code lines up the output report in key value pairs where the largest character count key name (the property name reported) will be spaced out along with all other names.

Here is an example result of a class instance with differing properties. Note that MemberOfAsList is a List<string> property which internally splits out the property MemberOf string (by its comma) into a list. This extension shows the list as a string.join of ", ".

DistinguishedName : CN=Write Frank,OU=Test,OU=Acme Industries,DC=amce-co,DC=acme,DC=net
CommonName        : Write Frank Lloyd
MemberOf          : CN=2042_Identity,CN=UserIdentities,CN=AlphaVision,DC=acme-co,DC=acme,DC=net
MemberOfAsList    : CN=2042_Identity, CN=UserIdentities, CN=AlphaVision, DC=acme-co, DC=acme, DC=net
otherTelephone    : 303-555-555
Name              : Wright Frank
WhenChanged       : 3/17/2014 9:04:06 PM
LogonCount        : 0

Extension Method

The following is an extension method whose goal is to reflect the type being passed in, determine the sizing of the data for output and then reports the properties each on a different line. String lists values are specified by a , (comma and space) separator between each value.

public static string ReportAllProperties<T>(this T instance) where T : class
{

    if (instance == null)
        return string.Empty;

    var strListType = typeof(List<string>);
    var strArrType  = typeof(string[]);

    var arrayTypes   = new[] { strListType, strArrType };
    var handledTypes = new[] { typeof(bool), typeof(Int32), typeof(String), typeof(DateTime), typeof(double), typeof(decimal), strListType, strArrType };

    var validProperties = instance.GetType()
                                  .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                  .Where(prop => handledTypes.Contains(prop.PropertyType))
                                  .Where(prop => prop.GetValue(instance, null) != null)
                                  .ToList();

    var format = string.Format("{{0,-{0}}} : {{1}}", validProperties.Max(prp => prp.Name.Length));

    return string.Join(
             Environment.NewLine,
             validProperties.Select(prop => string.Format(format, 
                                                          prop.Name,
                                                          (arrayTypes.Contains(prop.PropertyType) ? string.Join(", ", (IEnumerable<string>)prop.GetValue(instance, null))
                                                                                                  : prop.GetValue(instance, null)))));
}

Usage

public override string ToString()
{
    return ( this.ReportAllProperties() );
}

Test & Results

var test = new MyClass("Admin") { Name = "Omegaman", 
                                  ID = 1,  
                                  StartDate = DateTime.Now,
                                  AccessPoints = new List<string> { "Alpha", "Beta", "Gamma" },
                                  WeekDays = new string[]{ "Mon", "Tue" }
                                 };

 Console.WriteLine (test.ToString());

/*
Name         : Omegaman
ID           : 1
Role         : Admin
AccessPoints : Alpha, Beta, Gamma
WeekDays     : Mon, Tue
StartDate    : 3/18/2014 12:16:07 PM
*/

....

public class MyClass
{
    public string Name               { get; set; }
    public int ID                    { get; set; }
    private string Role              { get; set; }
    public List<string> AccessPoints { get; set; }
    public string[] WeekDays         { get; set; }    
    public DateTime StartDate        { get; set; }

    public MyClass(string role)
    {
        Role = role;
    }

    public override string ToString()
    {
       return ( this.ReportAllProperties() );
    }

}

Done!

Share

Tags: , , , ,

C#: Reflect and Load Entities From a DataSet using a Generic Method and Attributed Entities

iStock_000011856107XSmall If one is not using Linq-To-Sql and the entities are not being generated and loaded, one has to create their own entities and manually load the data into the it. Sure the process for doing one or two entities is ok when done by hand; but it becomes very repetitive grunt work for two or more. This article shows how to decorate an entity with attributes and then using reflection in a generic method load the data from a dataset in C#. This can be done with any version of .Net from 3.5 or greater.

Entity

To make this magic happen we need to decorate our entity with a C# attribute which describes the target column name in the database. Thanks to the System.Xml.Serialization namespace we can use the XmlElement attribute. It has an attribute within itself the ElementName attribute which is an excellent vehicle for what we need to do.

In the class below we have two strings, a DateTime and a decimal. Using the XmlElement we define what all of the target database column names are for each individual mapping of the property to hold the data.

public class Site
{

    [XmlElement(ElementName = "ID")]
    public decimal ID { get; set; }

    [XmlElement(ElementName = "Site_Code")]
    public string Code { get; set; }

    [XmlElement(ElementName="Site_Description")]
    public string Description { get; set; }

    [XmlElement(ElementName = "REQ_PROP_ORIG")]
    public DateTime? Origination { get; set; }

}
Using

Here are the usings if you don’t want to do <CTRL><.> on each error in the file to resolve the namespace for the next sections code.

using System.Reflection;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Globalization;
Generic Method and Reflection

Here is the generic method in a static class. In the next section I describe what is going on when this class is called with a data row and the target entity instance is returned. (See the section Example Usage below to see it in action.)

public static class EntityHelper
{

    public static TEntity CreateEntityFromDataRow<TEntity>(DataRow drData)
        where TEntity : class, new()
    {

        Attribute aTargetAttribute;
        Type tColumnDataType;

        TEntity targetClass = new TEntity();

        Type targetType = targetClass.GetType(); // The target object's type

        PropertyInfo[] properties = targetType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

        // Enumerate the properties and each property which has the XmlElementAttribute defined match the column name
        // and set the new objects value..
        foreach (PropertyInfo piTargetProperty in properties)
        {
            aTargetAttribute = Attribute.GetCustomAttribute(piTargetProperty, typeof(XmlElementAttribute));

            if (aTargetAttribute != null)
            {
                try
                {
                    foreach (DataColumn column in drData.Table.Columns)
                    {

                        if (((XmlElementAttribute)aTargetAttribute).ElementName.ToUpper() == column.ColumnName.ToUpper())
                        {

                            if (drData[column.ToString()] != DBNull.Value) // Only pull over actual values
                            {
                                tColumnDataType = drData[column.ToString()].GetType();

                                // Is the data in the database  a string format and do we
                                // want a DateTime? Do the below checks and if so covert to datetime.
                                if ((tColumnDataType != null) &&
                                    (tColumnDataType == typeof(System.String)) &&
                                    (piTargetProperty.PropertyType.IsGenericType) &&
                                    (piTargetProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) &&
                                    ((new NullableConverter(piTargetProperty.PropertyType)).UnderlyingType == typeof(System.DateTime)))
                                {
                                    // The below pattern dd-MMM-YY is for an Oracle date target. You may need to change this depending
                                    // on the database being used.
                                    DateTime dt = DateTime.ParseExact(drData[column.ToString()].ToString(), "dd-MMM-YY", CultureInfo.CurrentCulture);
                                    piTargetProperty.SetValue(targetClass, dt, null);
                                }
                                else // Set the value which matches the property type.
                                    piTargetProperty.SetValue(targetClass, drData[column.ToString()], null);
                            }
                            break; // Column name and data associated, no need to look at the rest of the columns.
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(string.Format("Load Failure of the Attribute ({0}) for {1}. Exception:{2}",
                        ((XmlElementAttribute)aTargetAttribute).ElementName, targetType.Name, ex.Message));
                }
            }
        }

        return targetClass;
    }
}
Explanation
  • Line 4: The generic method is defined to accept a generic type definition (the entity we are working with) but accept a DataRow as the actual data and return the generic type as a valid instance.
  • Line 5: This line requires that the generic type is a class and can be new’ed up. New because we will creating new entity instance at run time. See line 10.
  • Line 11: Simply new up a new entity to return.
  • Line 13/15: We begin to examine the generic type which will lead to the discovery of the properties we are looking at. Note we want all properties regardless of their access level. You can specify just public or private by removing the flags setup on line 14. (For more on this see my blog article .Net Reflection 101: Accessing The String Properties of an Active Object).
  • Line 19: We will enumerate upon the reflected properties of the type and match by reflected Element Name to Column Name.
  • Line 21: Here we reflect and get the custom attributes of the type for usage later.
  • Line 27: Now we begin to find the associated column by enumerating over each column found in the row.
  • Line 30: Does the reflected name match the current column name?
  • Line 35: What is the reported data type from the current row column? This is usede in the if of 39-43.
  • Line 39-43: Some databases return a string value for specific dates/times. If that is the case and we are looking at a string held date value do specialized processing to extract the date/time. If your database returns a DateTime object you can remove this if check.
  • Line 51: Assign the data in the column to the instances property via reflection in SetValue.
Example Usage
List<Site> SiteList = new List<Site>();

DataSet ds = new DataSet();

{Data Adaptor}.Fill( ds ); // Fill the dataset from a data adapter. 

// Convert the data in the dataset into a list of the target types.
foreach (DataRow dr in ds.Tables[0].Rows)
    SiteList.Add(EntityHelper.CreateEntityFromDataRow<Site>(dr));
Share

Tags: ,

.Net Reflection 101: Accessing The String Properties of an Active Object

Part of why I write some of these articles are to remind myself on how to do things. If one doesn’t do them every day they get lost with the rest of life’s memories. One of the topics I run into every so often is the need to enumerate an object and extract or set values of its properties. In this example I will create a generic function which will take in a class object and write out all of the public properties, the set those public properties.

Example

Here is the class we will reflect and notice it contains public and private properties.

The following code demonstrates how to enumerate over an object, list its properties and their values. It is divided into three static methods.
  1. The first method TestIT is the actual test method which can be called to show the operations for it creates a TestClass object to be reflected. This is used only for debug / show purposes.
  2. The second static OutputProperties shows the differences in how reflection of a class can change the values and a gotcha which gets all developers.
  3. The final method  EnumerateProperties simply enumerates over the reflected properties and prints them out.
public static void TestIT()
{
     TestClass tc = new TestClass( "AValue", "BValue", "CValue" );

     OutputProperties<TestClass>( tc );

     Console.WriteLine( Environment.NewLine );
}

public static void  OutputProperties<T>( T target )
{
     Type targetType = target.GetType();

     PropertyInfo[] propertiesdefaultPublic, propertiesSameAsDefault, propertiesPublicPrivate;

     propertiesdefaultPublic = targetType.GetProperties( );
     propertiesSameAsDefault = targetType.GetProperties( BindingFlags.Instance | BindingFlags.Public );
     propertiesPublicPrivate = targetType.GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );

     EnumerateProperties<T>( target, propertiesdefaultPublic, "Default -> ()" );
     EnumerateProperties<T>( target, propertiesSameAsDefault, "Same as Default"   );
     EnumerateProperties<T>( target, propertiesPublicPrivate, "Public And Private"  );
}

private static void EnumerateProperties<T>( T target, PropertyInfo[] properties, string Title )
{
 Console.WriteLine( "{0}------- {1} --------{0}", Environment.NewLine, Title );
 foreach (PropertyInfo prp in properties)
 {
     if (prp.PropertyType == typeof( string ))
         Console.WriteLine( string.Format( "({0}):  {1}", prp.Name, prp.GetValue( target, null ) ) );
 }
}
  • Line 03: Creates the target instance with three values to fill the properties.
  • Line 10: This generic method takes the class type and and actual instance of the type.
  • Line 12: What are we looking at? GetType tells us that.
  • Line 16: Here is the big gotcha! Everyone calls the default incarnation which only returns public properties!
  • Line 17: To achieve what the default does, we have to add two different flags. The key one is instance or we won’t reflect anything!
  • Line 18: This is the call which will get the private and public properties…avoids the gotcha of calling the default.
  • Line 26: We will display the properties and data of the instanced class T.
  • Line 29: Enumerate over the properties of the *TYPE*. This is not the actual instance.
  • Line 31: Only do the strings.
  • Line 32: prp.Name gets the name of the property. While GetValue requires that we pass in the actual instantiated object instance to see an actual values. Null is used because we don’t have an indexed type. Its just a string.

Here is the output:

------- Default -> () --------
(AProp):  AValue
(BProp):  BValue

------- Same as Default --------
(AProp):  AValue
(BProp):  BValue

------- Public And Private --------
(AProp):  AValue
(BProp):  BValue
(CProp):  CValue

To set a value, that is the reverse of GetValue which is found by SetValue below and has the same prerequisites:

private static void SetProperties<T>( T target, PropertyInfo[] properties )
{
    int count = 0;

    foreach (PropertyInfo prp in properties)
        prp.SetValue( target, string.Format( "NewValue{0}", ++count ), null );

}

If we were to do a run by just using the Public and Private properties array as used above gives us the below. The first print out set is what was above with our default values. The second after the call to SetProperties example above which has changed the values:

------- Public And Private --------
(AProp):  AValue
(BProp):  BValue
(CProp):  CValue

Call to SetValue() and the GetValue():

------- Public And Private --------

(AProp):  NewValue1
(BProp):  NewValue2
(CProp):  NewValue3
Share

Tags: ,

Reflect Interface from Unknown Assembly in C#

I had a need to scan a directory for assemblies and load (instantiate) a specific interface from the foreign assembly. The idea was that the application would work with a plugin architecture which would allow for an outside foreign assembly to be dropped in. Upon startup, the application would look into the directory and instantiate the plugin via its interface. (Note this is .Net 2 code and .Net 3.5 has a plugin architecture but the concepts of reflection are what are important in this article).

The following code will accept a filename of the assembly and attempt to load the interface in question. If it succeeds it returns the interface:

private IPlugin LoadPlugin( string AssemblyFileName )
{
 IPlugin PluginFound = null;
 Type iPluginType = typeof(IPlugin);

 Assembly _Assembly = Assembly.LoadFrom(AssemblyFileName);

 if (_Assembly != null)
 {
   Type[] types = _Assembly.GetExportedTypes();

   foreach (Type t in types)
    if (iPluginType.IsAssignableFrom(t))
    {
     IPlugin operation = Activator.CreateInstance(t) as IPlugin;

     if (operation != null) // Found!
     {
       PluginFound = operation;
       break;
     }
    }
   }

   return PluginFound;
  }
}

Here is what is going on:

  • Line 1 : The fully qualified filename is passed into the method.
  • Line 3 : The instantiated object if found, to be returned in this reference.
  • Line 4 : The actual type we are interested in.
  • Line 10 : Reflect the types found in the foreign assembly.
  • Line 13 : Is the current type the same as what we are looking for?
  • Line 15 : Try creating an instance.
  • Line 17 : Test the cast from line 15. If it is not null. We have a valid instance.
Share

Tags: , , ,

C#: Using Reflection to Instantiate a Generic Class in .Net

Reflection has many purposes, but what happens if one wants to instantiate a generic class? How does one specify the what makes the class generic to  instantiate it? The trick is to use the MakeGenericType to make the argument(s) and then call create Instance. Here is a code snippet:

Type d1 = typeof(List<>);

Type[] typeArgs = { typeof(string) };

Type makeme = d1.MakeGenericType(typeArgs);

object o = Activator.CreateInstance(makeme);

List<string> itsMe = o as List<string>;

Console.WriteLine((itsMe == null) ? "Failed" : "Succeeded");

Here is what is going on

  • Line 1 We get the type as normal.
  • Line 3 Create an array of the arguments we are interested in.
  • Line 5 Call MakeGenericType to do the magic
  • Line 7 Create the object.
Share

Tags: , ,