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
}
}
source to share
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).
source to share
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, ", "));
}
source to share