2013-02-12 52 views
3

我曾经见过这种使用过的模式/方法,我试图重新创建它以使我现有的一些代码更高效。使用Action委托根据泛型调用正确的函数

用例: 从源系统检索复杂对象。只有一部分信息会被客户端使用,所以我们必须将这个复杂的对象映射到JSON序列化的简单POCO;另外,在这种映射方法中,还有一些其他的数据格式化。首先,我们通过我们的复杂的对象为,做一些基本的处理

// 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 
    } 
} 
+0

的这另一个方面是,之间的对象的属性名称复杂和简单的对象可能不一样,部分逻辑和目的是制作JSON传递给调用者的包尽可能小。我只想避开任何有关为什么我需要映射功能的问题。 – AnthonyAlmighty 2013-02-12 15:13:44

+1

你有什么理由必须自己编写所有这些吗?你为什么不使用[AutoMapper](https://github.com/AutoMapper/AutoMapper/wiki/Getting-started)? – 2013-02-12 15:14:14

+0

当对象实际上是1对1时,我使用automapper,但是有时候转换过程需要做一些繁重的工作,而且我没有看到Automapper帮助我的方式。尽管这可能完全是我的无知。 – AnthonyAlmighty 2013-02-12 16:23:29

回答

2

我不太清楚你问什么,但这样的事情,你想要什么泛型方法?

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); 
    } 
    //.... 
} 

古称:

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

(注意在参数缺少())。

+0

是的!这工作!很好的回答和停止使用反射的好方法。 – AnthonyAlmighty 2013-02-12 16:30:43

+1

作为奖励,它会在编译时告诉你它是否找不到支持你正在尝试的特定翻译的'MapObject()'版本。 – Bobson 2013-02-12 17:46:11

0

看起来你可能会在这里实现Proxy Pattern。 否则,可能将逻辑移至实际对象本身,并在每个知道如何序列化自身的ComplexObjects中添加ToJSON()方法。然后将它们附加在一起以生成JSON数组。这取决于你使用什么来序列化JSON,所以在下面的例子中,我只是手动完成了。

公共JSONSerializable接口

public interface IJsonSerializable 
    { 
     string ToJson(); 
    } 

复杂和简单对象:

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 
    } 

然后进入点

 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, ", ")); 
     }