0

I am creating a library that pulls HTML tables from the web and converts them to objects. I have a ColumnConfigurator object that pre-configures how a specific table is laid out:

config.Column().Text().MapTo(/*Class.TextPropertyName*/); //What I want to be able to do
config.Column().Date().MapTo(/*Class.DatePropertyName*/);

The above code is the general idea of what I want to be able to do in the configuration (note that the first function creates a new column and returns it, and the subsequent methods set the object's configuration), and then when the table is being mapped to I'd like to retrieve the parameter passed into MapTo and have it automatically resolve to the correct property of a given object.

Here's what's confusing me the most: I want to make the main table object generic (ParsingTable<T>) so that theoretically any object can be mapped to. This means that none of the properties are available ahead of time. I'd like to pass the T.Property into the method so it knows how to automap. Is there a way to do this? I've read a small bit about reflection but heard it's bad for performance.

w0f
  • 908
  • 9
  • 23
  • You have a lot going on here so its not easy to understand what exactly you are asking. If you want to have syntax like this: `var item = config.SomeMethod().SomeOtherMethod();` then you need **extension methods**. If you want to use generics with set properties without reflection you need to find a common abstract (i.e interface, abstract class, base class) and restrict your generic method to that abstract. Then you'll be able to access any of the members of that abstract from your generic method. – maccettura Jun 28 '17 at 18:43

1 Answers1

1

For information on creating a fluent interface (what you are doing for the configuration), see here: creating API that is fluent

For the MapTo method to accept the property name from a generic class, you will end up with something like this:

public class ParsingTable<T>
{
   /*** All the other stuff ***/

   public static IColumnConfiguration MapTo(this IColumnConfiguration config, Expression<Func<T, object>> property)
   {
      if (property.Body is MemberExpression)
      {
         config.Property = (property.Body as MemberExpression).Member as PropertyInfo;
      }
      else
      {
         config.Property = (((UnaryExpression)property.Body).Operand as MemberExpression).Member as PropertyInfo;
      }
   }
}

public interface IColumnConfiguration
{
     PropertyInfo Property { get; set; }
}

Then when you are doing the parsing, you would call the PropertyInfo.SetValue() function for each value/column.

You are correct that this will likely be a little on the slower end compared to a direct property set. It depends highly on your situation if this is a big deal or not. The next step would be to compile a lambda expression for each column set if you really want to avoid the SetValue() call.

Note, I took some of the code above from here: http://blog.raffaeu.com/archive/2010/06/26/how-to-write-fluent-interface-with-c-and-lambda.aspx

Michael Weinand
  • 401
  • 2
  • 4