Use an Action delegate to call the correct function based on a generic type

I've seen this pattern / approach used before and I'm trying to recreate it to make some of my existing code more efficient.

Usage example: A complex object is retrieved from the source system. The client can only use a subset of the information, so we have to "map" this complex object to a simple POCO series for JSON; in addition, different data formatting is performed in this mapping method. First, we pass our complex object into a generic method that does some basic processing

// Generic Method, Entry Point for mapping
static void GenericEntry<T, TK>(string userid, string environment, DBContext context) {

    .... // do stuff with userid and environment to set a context
    .... // query results, which return a complex object of Type TK

    // Here is where I would like to use an Action delegate to call the appropriate map
    // method.. there could hundreds of objects that map and process down to a POCO, 
    // Currently, this logic is using reflection to find the appropriate method with 
    // the appropriate signature... something like: 
    Type functionType = typeof(DTOFunctions);
    var methods = functionType.GetMethods(BindingFlags.Public | BindingFlags.Static);
    var mi = methods.FirstOrDefault(x => x.Name == "MapObject" && 
        x.ReturnType == typeof(T));

    if (mi == null) throw new ArgumentException(string.Format("Unable to find method MapObject for {0}", typeof(TK).Name));

    var resultList = new ArrayList();
    foreach (var row in results)
    {
        var poco = mi.Invoke(functionType, new object[] { row });
        resultList.Add(poco);
    }
    if (resultCount == -1) resultCount = resultList.Count;
    return SerializeDTO(resultList, ResponseDataTypes.JSON, resultCount);

    // THERE HAS TO BE A BETTER WAY STACKOVERFLOW! HALP!
} 

public Class DTOFunctions {
    // Mapping Method from Complex to Simple object
    static SimplePOCO_A MapObject(ComplexObject_A cmplx){
        var poco = new SimplePOCO_A(); 
        .... // mapping from cmplx field to SimplePOCO field
    }

    static SimplePOCO_B MapObject(ComplexObject_B cmplx) {
        var poco = new SimplePOCO_B(); 
        .... // mapping from cmplx field to SimplePOCO fiel
    }
}

      

+3


source to share


2 answers


I'm not really sure what you are asking, but something like this, what do you want?

static void GenericEntry<T, TK>(string userid, string environment, 
                                DBContext context, Func<T, TK> conversion) 
{
    //....
    var resultList = new List<TK>();
    foreach (var row in results)
    {
        var poco = conversion(row);
        resultList.Add(poco);
    }
    //....
}

      

Called as:



 GenericEntry<ComplexObject, SimplePOCO>(userid, environment, context, DTOFunctions.MapObject)

      

(Note the absence ()

in the argument).

+2


source


It looks like you could implement a proxy pattern here. Otherwise, perhaps move the logic to actual objects and add a ToJSON () method to each of the ComplexObjects that knows how to serialize itself. Then add them together to create a JSON array. It will depend on what you are using to serialize the JSON, so in the example below, I just did it manually.

JSONSerializable generic interface

    public interface IJsonSerializable
    {
        string ToJson();
    }

      

Complex and simple objects:



    public class ComplexObjectA : IJsonSerializable
    {
        public string ToJson()
        {
            var simpleObject = new SimpleObjectA();

            // Map away

            // Then serialize
            return SerializeDTO(simpleObject);
        }

        private string SerializeDTO(SimpleObjectA simpleObject)
        {
            throw new NotImplementedException();
        }
    }

    public class SimpleObjectA
    {
        // simple properties
    }

      

And then the entry point

        static void GenericEntry<T, TK>(string userid, string environment, DBContext context)
        {

            // Magic happens here
            var results = GetResults();

            // More magic

            var resultList = new List<string>();
            foreach (var row in results)
            {
                var poco = row.ToJson();
                resultList.Add(poco);
            }
            return String.Format("[{0}]", String.Join(resultList, ", "));
        }

      

0


source







All Articles