反射:反射是相當強大的一個機制,它允許在運行時發現並使用編譯時還不了解的類型及其成員;
委托:System.Delegate提供了幾個方法,在編譯時不知道委托的某些必要信息時,利用本身提供的幾個方法創建並調用一個委托,CreateDelegate、DynamicInvoke。
在做MVC項目或者WebAPI項目時,經常會遇到JS和后台動態交互的情況,按照以前的邏輯是每個請求對應不同的URL(即不同的后台Action),久而久之造成很難維護的局面,讓人尷尬萬分,
$.get("/Home/Action4", { item1: "1" }, function (data) {
alert(data);
});
$.get("/Home/Action3", { item1: "2" }, function (data) {
alert(data);
});
$.get("/Home/Action2", { item1: "3" }, function (data) {
alert(data);
});
$.get("/Home/Action1", { item1: "4" }, function (data) {
alert(data);
});
每個頁面有幾個交互,不同的頁面又有很多不同的交互,每個模塊。。。。。。。
但是現在借助偉大的.net平台提供的反射和委托機制,我們終於可以改變這種混亂的局面,統一前端和后台數據交互的入口:
優勢自不必說,下面是一個測試案例:
前端Ajax請求部分:
<script type="text/javascript">
$.get("/Home/DynamicEnvoke", { item1: "NumChars|OneString|4362846327846328" }, function (data) {
alert(data);
});
$.get("/Home/DynamicEnvoke", { item1: "SubTract|TwoInt32s|2|1" }, function (data) {
alert(data);
});
</script>
既然是統一入口,所以可以看到URL不再變化,變化的只是傳入的參數,每個參數用|分隔,至於客戶端的URL可以封裝成常量或其他辦法。
DynamicEnvoke是什么? 一個后台的入口Public的方法,傳遞的參數僅僅是一個字符串類型的參數,這里可以重寫Model綁定機制來支持更高級的模型類型(如數組、集合、字典,復雜類型,具體參考
通過實例模擬ASP.NET MVC的Model綁定機制:數組系列文章):
public object DynamicEnvoke(string item1)
{
var args = item1.Split('|');
Type deltype = Type.GetType(args[1]);
if (deltype == null)
{
Console.WriteLine("invalid deltype args");
return null;
}
Delegate del = null;
try
{
var mi = typeof(HomeController).GetMethod(args[0], BindingFlags.NonPublic | BindingFlags.Static);
del = Delegate.CreateDelegate(deltype, mi);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString()); return null;
}
object[] callbackargs = new object[args.Length - 2];
if (del.GetType() == typeof(TwoInt32s))
{
for (int i = 2; i < args.Length; i++)
{
callbackargs[i - 2] = Int32.Parse(args[i]);
}
}
else if (del.GetType() == typeof(OneString))
{
Array.Copy(args, 2, callbackargs, 0, callbackargs.Length);
}
var result = del.DynamicInvoke(callbackargs);
return result;
}
這是整個解決方案的關鍵所在,主要是構建一個Delegate對象然后調用DynamicInvoke方法,調用DynamicInvoke時,它會保證在內部傳遞的參數與回調方法期望的參數一致,否則拋出異常,
執行完成后返回回調方法的返回值,當然了這只是一個測試的示例,還有很多需要修改和完善的地方。
后台完整代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
internal delegate object TwoInt32s(Int32 n1, Int32 n2);
internal delegate object OneString(string str);
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public object DynamicEnvoke(string item1)
{
var args = item1.Split('|');
Type deltype = Type.GetType(args[1]);
if (deltype == null)
{
Console.WriteLine("invalid deltype args");
return null;
}
Delegate del = null;
try
{
var mi = typeof(HomeController).GetMethod(args[0], BindingFlags.NonPublic | BindingFlags.Static);
del = Delegate.CreateDelegate(deltype, mi);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString()); return null;
}
object[] callbackargs = new object[args.Length - 2];
if (del.GetType() == typeof(TwoInt32s))
{
for (int i = 2; i < args.Length; i++)
{
callbackargs[i - 2] = Int32.Parse(args[i]);
}
}
else if (del.GetType() == typeof(OneString))
{
Array.Copy(args, 2, callbackargs, 0, callbackargs.Length);
}
var result = del.DynamicInvoke(callbackargs);
return result;
}
public ViewResult Home()
{
return View();
}
private static object Add(int n1, int n2)
{
return n1 + n2;
}
private static object SubTract(Int32 n1, Int32 n2)
{
return n1 - n2;
}
private static object NumChars(string str)
{
return str.Length;
}
private static object Reverse(string str)
{
Char[] chars = str.ToCharArray();
Array.Reverse(chars);
return new String(chars);
}
}
}
前端完成代碼:
@{ ViewBag.Title = "Home"; } <script src="~/Content/jquery-1.9.1.min.js"></script> <script type="text/javascript"> $.get("/Home/DynamicEnvoke", { item1: "NumChars|OneString|4362846327846328" }, function (data) { alert(data); }); $.get("/Home/DynamicEnvoke", { item1: "SubTract|TwoInt32s|2|1" }, function (data) { alert(data); }); </script>
下面送上一首情詩:《花痴》

