开发者

Returning a function pointer

开发者 https://www.devze.com 2022-12-12 04:53 出处:网络
I\'m trying to create a url builder similar to the one in asp mvc except our methods are frequently changing parameters and breaking pages.

I'm trying to create a url builder similar to the one in asp mvc except our methods are frequently changing parameters and breaking pages.

Does anyone know if it's possible to coerce c# into allowing event like syntax to be returned from a delegate like this:

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

The class would be similar to this:

public class UrlBuilder<开发者_Python百科TController>
{
    public UrlBuilder2(Func<TController, TType> action)
    {
    }
}

Basically I want to know what Type to use for TType. Or if it's at all possible.

Edit - I would (if possible) like to use just the method, similar to how you would assign an event ( clickEvent =+ myMethod;)


Not exactly sure what you want to achieve, but assuming you want to generate link simlar to this:

MyForm/MyMethod.aspx

based on WebForm (or any other class) like this:

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

You can use this builder (test included):

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

All this will allow you to keep the links type-safe and refactoring advantages will be leveraged.
You will probably need to enhance the UrlBuilder2 but this should get you started.


If you just want to use name of a method to generate links you can do something like this:

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

The tricky thing is correctly resolving the Expression tree. The code above works for this particular sample, but you will need to check it works for all your cases.


You can return a function pointer aka a delegate in c# as below.

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

This would allow you to attach the output of the function to an event.

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

Assuming that someevent took a function with the same signature as the delegate.

0

精彩评论

暂无评论...
验证码 换一张
取 消