2009-11-20 169 views
0

我想创建一个类似于asp mvc中的url生成器,除了我们的方法经常更改参数和中断页面。返回一个函数指针

有谁知道,如果有可能迫使C#为允许从一个委托返回语法类似事件是这样的:基本上

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

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

类是类似于此我想知道什么类型用于TType。或者如果可能的话。

编辑 - 我会(如果可能)喜欢用刚才的方法,类似于你将如何分配事件(clickEvent =+ myMethod;

回答

1

不清楚自己想要达到的目标,但假设你想生成链接simlar这样:

MyForm/MyMethod.aspx 
基于web窗体(或任何其他类)这样

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

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

+0

有了这个,如果我向MyMethod添加一个参数,那么它仍然会在任何地方使用表达式链接到它。这是我想要避免的。 – flukus

+0

不会。它甚至不会编译。 我加了如何将参数传递给查询字符串的方法。 –

+0

这实质上就是现有的URl生成器所做的。我会(如果可能的话)喜欢使用方法,类似于您将如何分配事件(clickEvent = + myMethod;) – flukus

0

您可以像下面那样在c#中返回一个函数指针aka a delegate。

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采用与代表相同签名的函数。

+0

这将需要一个代表每个可能的控制器操作,所以不是很优雅。 – flukus

+0

您可以通过泛型创建各种委托签名,例如 public delegate T myreturningdelegate (); –