我正在原型化一种在C#MVC(4)应用程序中声明路由的自动方式,所以我决定使用自定义属性来控制器的方法:
[RouteUrl("foo/{param}")]
[RouteConstraint("param", "[a-z]+[0-9]+")]
public ActionResult MyAction(string param)
{
return View();
}
自定义属性允许我分别收集信息,然后我可以将这对夫妇参数/约束存储在一个字典中。
问题是在RouteCollection.MapRoute()内部调用的new Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, ...)
,仅作为参数RouteValueDictionary(IDictionary<string,object>)
或RouteValueDictionary(object)
用于默认值和约束。
所以我不知道如何将值对转换为对象(或转换为RouteValueDictionary)。
是否可以将Dictionary转换为PHP中的对象?
(object)array("prop1" => "value1", "prop2" => "value2", ...)
也许我应该采取不同的方法,任何想法?
答案 0 :(得分:1)
嗯,我刚刚意识到Dictionary<string, object>
与Dictionary<string, string>
兼容,所以我能够做我想做的一切。
答案 1 :(得分: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]);
}
另请参阅github上提供的DynamicSugar.net
答案 2 :(得分:0)
你在找这个吗?
(object) new { prop1 = "value1", prop2 = "value2", ...}
答案 3 :(得分: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"}
});