gpt4 book ai didi

c#-2.0 - 在运行时创建和存储方法链的方法

转载 作者:行者123 更新时间:2023-12-02 18:57:28 25 4
gpt4 key购买 nike

我遇到的问题是,我需要进行大约 40 多次转换才能将松散类型信息转换为存储在 db、xml 文件等中的强类型信息。

我计划用元组标记每种类型,即像这样的转换形式:

host.name.string:host.dotquad.string

它将提供从输入到输出形式的转换。例如,名称存储在字符串类型的主机字段中,输入将转换为字符串类型的点四符号并存储回主机字段。更复杂的转换可能需要几个步骤,每个步骤都通过方法调用来完成,因此是方法链接。

进一步检查上面的示例,元组“host.name.string”的字段主机名为 www.domain.com。完成 DNS 查找以将域名转换为 IP 地址。另一种方法是将 DNS 查找返回的类型更改为 string 类型的 dotquad 内部类型。对于此转换,调用了 4 个单独的方法来从一个元组转换为另一个元组。其他一些转换可能需要更多步骤。

理想情况下,我想要一个关于如何在运行时构造方法链的小例子。开发时方法链接相对简单,但需要一页又一页的代码来涵盖所有可能性,并进行 40 多次转换。

我想到的一种方法是在启动时解析元组,并将链写入程序集,编译它,然后使用反射来加载/访问。它真的很难看,并且会抵消我希望获得的性能提升。

我使用的是 Mono,所以没有 C# 4.0

如有任何帮助,我们将不胜感激。鲍勃。

最佳答案

这是一个使用 LINQ 表达式的快速但肮脏的解决方案。您已经表明您想要 C# 2.0,这是 3.5,但它确实可以在 Mono 2.6 上运行。方法链接有点hacky,因为我不完全知道你的版本是如何工作的,所以你可能需要调整表达式代码以适应。

真正的魔力确实发生在Chainer类中,它接受一个字符串集合,代表MethodChain子类。采取这样的集合:

{
"string",
"string",
"int"
}

这将生成一个像这样的链:

new StringChain(new StringChain(new IntChain()));

Chainer.CreateChain 将返回一个调用 MethodChain.Execute() 的 lambda。由于 Chainer.CreateChain 使用了一些反射,因此速度很慢,但它只需要为每个表达式链运行一次。 lambda 的执行速度几乎与调用实际代码一样快。

希望您能将其融入您的架构中。

public abstract class MethodChain {
private MethodChain[] m_methods;
private object m_Result;


public MethodChain(params MethodChain[] methods) {
m_methods = methods;
}

public MethodChain Execute(object expression) {

if(m_methods != null) {
foreach(var method in m_methods) {
expression = method.Execute(expression).GetResult<object>();
}
}

m_Result = ExecuteInternal(expression);
return this;
}

protected abstract object ExecuteInternal(object expression);

public T GetResult<T>() {
return (T)m_Result;
}
}

public class IntChain : MethodChain {

public IntChain(params MethodChain[] methods)
: base(methods) {

}

protected override object ExecuteInternal(object expression) {
return int.Parse(expression as string);
}
}

public class StringChain : MethodChain {

public StringChain(params MethodChain[] methods):base(methods) {

}

protected override object ExecuteInternal(object expression) {
return (expression as string).Trim();
}
}


public class Chainer {

/// <summary>
/// methods are executed from back to front, so methods[1] will call method[0].Execute before executing itself
/// </summary>
/// <param name="methods"></param>
/// <returns></returns>
public Func<object, MethodChain> CreateChain(IEnumerable<string> methods) {

Expression expr = null;
foreach(var methodName in methods.Reverse()) {

ConstructorInfo cInfo= null;
switch(methodName.ToLower()) {
case "string":
cInfo = typeof(StringChain).GetConstructor(new []{typeof(MethodChain[])});
break;
case "int":
cInfo = typeof(IntChain).GetConstructor(new[] { typeof(MethodChain[]) });
break;
}
if(cInfo == null)
continue;

if(expr != null)
expr = Expression.New(cInfo, Expression.NewArrayInit( typeof(MethodChain), Expression.Convert(expr, typeof(MethodChain))));
else
expr = Expression.New(cInfo, Expression.Constant(null, typeof(MethodChain[])));
}

var objParam = Expression.Parameter(typeof(object));
var methodExpr = Expression.Call(expr, typeof(MethodChain).GetMethod("Execute"), objParam);
Func<object, MethodChain> lambda = Expression.Lambda<Func<object, MethodChain>>(methodExpr, objParam).Compile();

return lambda;
}
[TestMethod]
public void ExprTest() {
Chainer chainer = new Chainer();
var lambda = chainer.CreateChain(new[] { "int", "string" });
var result = lambda(" 34 ").GetResult<int>();
Assert.AreEqual(34, result);
}
}

关于c#-2.0 - 在运行时创建和存储方法链的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3286160/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com