2

I have a class that helps me read data from an MS SQL database into a list of objects. For the most part it's pretty straightforward; I can assume the property name of the class matches the column name of the table and just assign it accordingly, but sometimes I need to be able to transform data.

I have created a custom attribute to put on my class properties:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TransformDataAttribute : Attribute
{
    public Func<object, string, object> TransformThisData { get; set; }
}

Now, let's say I want to create the Func on the fly, like this:

    [TransformData(TransformThisData = new Func<object, string, object>((v, p) => "My name is " + v.ToString()))]
    public string Name { get; set; }

The error that I am seeing is 'TransformThisData' is not a valid named attribute argument because it is not a valid attribute parameter type.

What is the best way to accomplish Func as a property attribute?

6
  • 2
    Only primitive constants or arrays of primitives can be used as attribute parameters. Commented Oct 16, 2014 at 22:27
  • Why do you need to specify the function as an attribute instead of just using a standard method in your class? Commented Oct 16, 2014 at 22:29
  • I wanted to be able to specify a specific function for transforming the data on a particular property. For example, I have a data table containing a column filled with weirdly mixed data in it. It is a string column either containing a string (which maps to an enum value) or a number (which you use to get the string value for the enum for that number) or a key word that maps to an enum value. Wish I could clean up the data but they require it this way. Commented Oct 16, 2014 at 22:53
  • I could just create a data transform function and have a select based on object/table name and property/column name but I was hoping to avoid that. Commented Oct 16, 2014 at 22:55
  • I could also just pass in a class name and a method name as string properties on the data attribute, and use them to transform the data, but I was hoping for something less Reflection based. Commented Oct 16, 2014 at 22:56

1 Answer 1

2

Well, here's the best I have been able to come up with.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TransformDataAttribute : Attribute
{
    public string TransformDataClass { get; set; }
    // This method must contain these parameters: (object value, PropertyInfo pi)
    public string TransformDataMethod { get; set; }
}

I put it on the class property, like so...

  public class Tracker
  {
    [TransformData(TransformDataClass = "CompanyTracker.DataTransformation", TransformDataMethod = "FunkyData")]
    public string FunkyData { get; set; }
  }

I can have a single data transformation class with different methods of transformation:

public class DataTransformation
{
    public object FunkyData(object value, PropertyInfo pi)
    {
        // if data is this, return that, blah, blah
        return value;
    }
}

A static utility method for interpreting the three parameters:

    public static object CallThisMethod(string className, string methodName, object[] parms)
    {
        Type type = Type.GetType(className);
        MethodInfo theMethod = type.GetMethod(methodName);
        object classInstance = Activator.CreateInstance(type);

        return theMethod.Invoke(classInstance, parms);
    }

...and then in my ADO Helper code, when it comes to assigning values to properties:

        TransformDataAttribute attr = Utility.GetPropertyAttribute<TransformDataAttribute>(pi);
        if (attr != null)
        {
            object[] parms = new object[] { value, pi };
            value = Utility.CallThisMethod(attr.TransformDataClass, attr.TransformDataMethod, parms);
        }
        pi.SetValue(t, value, null);

It works. I hate to depend on Reflection of embedded strings for classes and methods, and it just doesn't seem like good design, but sometimes you just have to get things done. If anyone has a more elegant way to do this I'd be glad to hear about it.

Sign up to request clarification or add additional context in comments.

1 Comment

As of C#6, you can use nameof() to at least get some compile-time validation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.