返回一个函数指针

时间:2009-11-20 05:20:40

标签: c#

我正在尝试创建一个类似于asp mvc中的url构建器,除了我们的方法经常更改参数和破坏页面。

有没有人知道是否有可能强制c#允许从这样的委托中返回类似语法的事件:

new UrlBuilder2<FakeController>(x => { return x.ActionWithInt; });

这个课程类似于:

public class UrlBuilder<TController>
{
    public UrlBuilder2(Func<TController, TType> action)
    {
    }
}

基本上我想知道TType使用什么类型。或者如果可能的话。

编辑 - 我会(如果可能的话)喜欢只使用方法,类似于分配事件的方式(clickEvent =+ myMethod;

2 个答案:

答案 0 :(得分:1)

不完全确定您想要实现的目标,但假设您想要生成链接simlar:

MyForm/MyMethod.aspx

基于WebForm(或任何其他类),如下所示:

public class MyForm {
  public void MyMethod() {
    // Something here
  }
  public void MethodWithParams(int i, string str) {
    // Something here
  }
}

您可以使用此构建器(包含测试):

class UrlBuilder2<T> {
    private readonly Expression<Func<T, object>> callExpression;

    public UrlBuilder2(Expression<Func<T,object>> callExpression) {
        this.callExpression = callExpression;
    }

    public override string ToString() {
        MethodCallExpression call = (MethodCallExpression) callExpression.Body;
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("{0}/{1}.aspx", call.Object.Type.Name, call.Method.Name);
        var delimiter = "?";
        var formalParams = call.Method.GetParameters();
        for (int i = 0; i < formalParams.Length; i++) {
            var actual = call.Arguments[i];
            if (actual == null)
                continue; // Do not put NULL to QueryString
            var formal = formalParams[i].Name;
            sb.AppendFormat("{0}{1}={2}", delimiter, formal, HttpUtility.HtmlEncode(actual.ToString()));
        }
        return sb.ToString();
    }
}

[Test]
public void CanBuildUrlByClassAndMethodName() {
    var str = new UrlBuilder2<MyForm>(c => c.MyMethod()).ToString();
    str.Should().Be.EqualTo("MyForm/MyMethod.aspx");
}

[Test]
public void CanBuildUrlByMethodWithParams() {
    var str = new UrlBuilder2<MyForm>(c => c.MethodWithParams(2, "hello")).ToString();
    str.Should().Be.EqualTo("MyForm/MyMethod.aspx?i=2&str=hello");
}

所有这些都可以让你保持链接类型安全,并且可以利用重构优势 您可能需要增强UrlBuilder2,但这应该可以帮助您入门。


如果您只想使用方法名称来生成链接,可以执行以下操作:

class MyClass {
    public void MyMethod() {}
}

class UrlBuilder3<T> {
    Expression<Func<T, Action>> info;
    public UrlBuilder3(Expression<Func<T, Action>> info) {
        this.info = info;                
    }

    public override string ToString() {
        UnaryExpression exp = (UnaryExpression)info.Body;
        MethodCallExpression createDelegate = (MethodCallExpression)exp.Operand;
        // 0-Action,1-x,2-Delegate as Constant
        ConstantExpression methodArgument = (ConstantExpression)createDelegate.Arguments[2];

        MethodInfo method = (MethodInfo)methodArgument.Value;
        return string.Format("{0}/{1}.aspx", typeof(T).Name, method.Name);
    }
}

[Test]
public void UrlByDelegate() {
    new UrlBuilder3<MyClass>(x => x.MyMethod).ToString()
        .Should().Be.EqualTo("MyClass/MyMethod.aspx");
}

棘手的是正确解析表达式树。上面的代码适用于此特定示例,但您需要检查它是否适用于您的所有情况。

答案 1 :(得分:0)

您可以返回一个函数指针,也就是c#中的委托,如下所示。

public delegate int mydelegate(string s);
public class Test
{
    mydelegate MyFunc(string s)
    {
        return (astring => astring.Length + s.Length);
    }
}

这将允许您将函数的输出附加到事件。

var test = new Test();
someevent += test.MyFunc("this is a test");

假设someevent采用了与委托具有相同签名的函数。