2013-03-01 49 views
0

我原型自动的方式在C#中的MVC(4)应用程序申报路线,所以我决定用控制器的方法自定义属性:动态转换属性的列表为对象

[RouteUrl("foo/{param}")] 
[RouteConstraint("param", "[a-z]+[0-9]+")] 
public ActionResult MyAction(string param) 
{ 
    return View(); 
} 

自定义属性允许我分别收集信息,然后我可以将这对夫妇参数/约束存储在字典中。

问题是new Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, ...)在RouteCollection.MapRoute()中被调用,只能作为参数RouteValueDictionary(IDictionary<string,object>)RouteValueDictionary(object)作为默认值和约束。

所以我不知道该怎么值的情侣转换成一个对象(或成RouteValueDictionary)。

是否有可能一个字典转换成一个对象就像在PHP?

(object)array("prop1" => "value1", "prop2" => "value2", ...) 

也许我应该采取不同的方法,任何想法?

+1

请不要推倒重来,而不是必须在[AttributeRouting项目]看看(https://github.com/mccalltd/AttributeRouting/wiki/Getting-Started) – nemesv 2013-03-01 20:11:01

+0

您是如何实际存储'param'处理后? – Bobson 2013-03-01 20:34:53

+0

我使用反射来选择具有自定义属性的控制器方法,然后将字典中属性值的参数名称存储在字典中。 – Profet 2013-03-01 20:40:34

回答

0

你在找这个?

(object) new { prop1 = "value1", prop2 = "value2", ...} 
+0

我不这么认为 - 我认为OP希望名称('prop1'和'prop2')也是可变的,根据输入。 – Bobson 2013-03-01 20:34:06

+0

不,它与'new {...}'相同:) 更多类似于php的内容:'$ obj =(object)null; foreach($ propertiesMap作为$ key => $ value){$ obj-> key = $ value}' – Profet 2013-03-01 20:46:13

1

嗯,我只是意识到Dictionary<string, object>是兼容Dictionary<string, string>所以我能够做所有我想要的。使用

0

像这样的事情))

public abstract class DynamicClass 
    { 
     public override string ToString() 
     { 
      PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("{"); 
      for (int i = 0; i < props.Length; i++) 
      { 
       if (i > 0) sb.Append(", "); 
       sb.Append(props[i].Name); 
       sb.Append("="); 
       sb.Append(props[i].GetValue(this, null)); 
      } 
      sb.Append("}"); 
      return sb.ToString(); 
     } 
    } 

    //DynamicTypeFactory 
    public static class ExpressionHelper //simplified 
    { 

     private const string DYNAMIC_ASSEMBLY_NAME = "DynamicAssembly"; 
     private const string DYNAMIC_MODULE_NAME = "DynamicModule"; 
     private const string DYNAMIC_CLASS_PREFIX = "DynamicClass"; 
     private static ModuleBuilder _moduleBuilder; 

     [SecurityCritical] 
     static ExpressionHelper() 
     { 
      //var assemblyName = new AssemblyName(DYNAMIC_ASSEMBLY_NAME); 

      AssemblyBuilder assembly = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName(DYNAMIC_ASSEMBLY_NAME), AssemblyBuilderAccess.Run); 
      assembly.GetName().SetPublicKey(Assembly.GetExecutingAssembly().GetName().GetPublicKey()); 
      assembly.GetName().SetPublicKeyToken(Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken()); 
      _moduleBuilder = assembly.DefineDynamicModule(DYNAMIC_MODULE_NAME, true); 

     } 

     public static Type CreateType(IDictionary<string, Type> propertyTypes) 
     { 
      var typeName = DYNAMIC_CLASS_PREFIX + propertyTypes.GetHashCode().ToString(); 
      TypeBuilder typeBuilder = _moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public, typeof(DynamicClass)); 
      FieldInfo[] fields = GenerateProperties(typeBuilder, propertyTypes); 
      GenerateEquals(typeBuilder, fields); 
      GenerateGetHashCode(typeBuilder, fields); 
      Type result = typeBuilder.CreateType(); 
      return result; 
     } 

     public static object CreateObject(IDictionary<string, object> propertyValues) 
     { 
      var propertyTypes = propertyValues.ToDictionary(pair => pair.Key, pair => pair.Value == null ? typeof(object) : pair.Value.GetType()); 
      var type = CreateType(propertyTypes); 

      Expression targetExpression = Expression.New(type.GetConstructors()[0]); 

      var lambda = Expression.Lambda(targetExpression); 
      var target = lambda.Compile().DynamicInvoke(); 

      List<MemberBinding> bindings = new List<MemberBinding>(); 

      foreach (var pair in propertyValues) 
      { 
       bindings.Add(Expression.Bind(type.GetProperty(pair.Key), Expression.Constant(pair.Value))); 
      } 
      return Expression.Lambda(Expression.MemberInit(Expression.New(type), bindings.ToArray())).Compile().DynamicInvoke(); 
     } 

     private static FieldInfo[] GenerateProperties(TypeBuilder typeBuilder, IDictionary<string, Type> propertyTypes) 
     { 
      FieldInfo[] fields = new FieldBuilder[propertyTypes.Count]; 
      for (int i = 0; i < propertyTypes.Count; i++) 
      { 
       var dp = propertyTypes.ElementAt(i); 

       var fb = typeBuilder.DefineField("<" + dp.Key + ">k__BackingField", dp.Value, FieldAttributes.Private); //HasDefault? 
       var pb = typeBuilder.DefineProperty(dp.Key, PropertyAttributes.HasDefault, dp.Value, null); 


       var mbGet = typeBuilder.DefineMethod("get_" + dp.Key, 
        MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
        dp.Value, Type.EmptyTypes); 

       var getterGenerator = mbGet.GetILGenerator(); 
       getterGenerator.Emit(OpCodes.Ldarg_0); 
       getterGenerator.Emit(OpCodes.Ldfld, fb); 
       getterGenerator.Emit(OpCodes.Ret); 
       //setterBuilder 
       MethodBuilder mbSet = typeBuilder.DefineMethod("set_" + dp.Key, 
        MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
        null, new Type[] { dp.Value }); 
       //setterILGenerator 
       var setterGenerator = mbSet.GetILGenerator(); 
       setterGenerator.Emit(OpCodes.Ldarg_0); 
       setterGenerator.Emit(OpCodes.Ldarg_1); 
       setterGenerator.Emit(OpCodes.Stfld, fb); 
       setterGenerator.Emit(OpCodes.Ret); 
       pb.SetGetMethod(mbGet); 
       pb.SetSetMethod(mbSet); 
       fields[i] = fb; 
      } 
      return fields; 
     } 

     private static void GenerateEquals(TypeBuilder typeBuilder, FieldInfo[] fields) 
     { 
      var mb = typeBuilder.DefineMethod("Equals", 
       MethodAttributes.Public | MethodAttributes.ReuseSlot | 
       MethodAttributes.Virtual | MethodAttributes.HideBySig, 
       typeof(bool), new Type[] { typeof(object) }); 
      var generator = mb.GetILGenerator(); 
      var other = generator.DeclareLocal(typeBuilder); 
      var next = generator.DefineLabel(); 
      generator.Emit(OpCodes.Ldarg_1); 
      generator.Emit(OpCodes.Isinst, typeBuilder); 
      generator.Emit(OpCodes.Stloc, other); 
      generator.Emit(OpCodes.Ldloc, other); 
      generator.Emit(OpCodes.Brtrue_S, next); 
      generator.Emit(OpCodes.Ldc_I4_0); 
      generator.Emit(OpCodes.Ret); 
      generator.MarkLabel(next); 
      foreach (var field in fields) 
      { 
       var ft = field.FieldType; 
       var ct = typeof(EqualityComparer<>).MakeGenericType(ft); 
       next = generator.DefineLabel(); 
       generator.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); 
       generator.Emit(OpCodes.Ldarg_0); 
       generator.Emit(OpCodes.Ldfld, field); 
       generator.Emit(OpCodes.Ldloc, other); 
       generator.Emit(OpCodes.Ldfld, field); 
       generator.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null); 
       generator.Emit(OpCodes.Brtrue_S, next); 
       generator.Emit(OpCodes.Ldc_I4_0); 
       generator.Emit(OpCodes.Ret); 
       generator.MarkLabel(next); 
      } 
      generator.Emit(OpCodes.Ldc_I4_1); 
      generator.Emit(OpCodes.Ret); 
     } 

     private static void GenerateGetHashCode(TypeBuilder typeBuilder, FieldInfo[] fields) 
     { 
      var mb = typeBuilder.DefineMethod("GetHashCode", 
       MethodAttributes.Public | MethodAttributes.ReuseSlot | 
       MethodAttributes.Virtual | MethodAttributes.HideBySig, 
       typeof(int), Type.EmptyTypes); 
      var generator = mb.GetILGenerator(); 
      generator.Emit(OpCodes.Ldc_I4_0); 
      foreach (FieldInfo field in fields) 
      { 
       var ft = field.FieldType; 
       var ct = typeof(EqualityComparer<>).MakeGenericType(ft); 
       generator.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); 
       generator.Emit(OpCodes.Ldarg_0); 
       generator.Emit(OpCodes.Ldfld, field); 
       generator.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null); 
       generator.Emit(OpCodes.Xor); 
      } 
      generator.Emit(OpCodes.Ret); 
     } 
    } 

var obj = ExpressionHelper.CreateObject(new Dictionary<string, object>() 
              { 
               {"testInt32Property", int.MaxValue}, 
               {"testStringProperty", "TestString"} 
              }); 
+0

谢谢,很高兴知道! C#有时非常肮脏^^ – Profet 2013-03-01 22:25:09

1

随着一些的C#4.0

Dictionary<string, object> dic = new Dictionary<string,object>() { 

    { "LastName", "Doe" }, 
    { "FirstName", "Joe" }, 
    { "Age", 35 } 
}; 

dynamic o = new System.Dynamic.ExpandoObject(); 

foreach(var e in dic) 
{ 
    var oo = o as IDictionary<String, object>; 
    oo[e.Key] = e.Value; 
} 

foreach(var a in o) 
{ 
    Console.WriteLine("{0}={1}", a.Key, (o as IDictionary<String, object>)[a.Key]); 
} 

动态特性也期待在DynamicSugar.net可在github上