0

我有一个小型路由引擎。它匹配模式并填充路由参数字典。所以/blog/{action}/{id}将匹配/blog/view/123123作为值放入id字典中的键等等。

有趣的部分来了。我想改变这个系统来代替使用模型类型的架构,所以我可以有类似的东西

class BlogRoute
{
    [RouteParam("action")]
    public string Action{get;set;}
    [RouteParam("id")]
    public string ID{get;set;}
}

当然,还有其他路线“模型”/comments/{action}/{entryid}/{id}等等,所以我需要这样做我相信通过反思

我的最终目标基本上是拥有类似AddRoute("pattern", new BlogRoute())或类似的东西,并且我的路由器将数据动态填充到 BlogRoute 实例中

我将如何开始这样做?我几乎没有使用反射(虽然奇怪地非常熟悉 IL),而且它看起来有点令人生畏,我害怕以次优的方式来做它,因为这对性能有点关键。这也在多个其他库中完成。基本上每个 ORM 都会做类似的事情。是否有任何教程或类似的东西可以开始这样的事情?

4

1 回答 1

1

只需浏览具有 RouteParam 属性的属性。如果获取传递给属性的构造函数的值和传递给AddRoute的某个路由信息对象上的属性本身的值,就可以获得所有的路由信息​​。

我不确定反射是否明显缓慢,但在性能关键的情况下我会远离它。您可以将这种使用反射的方法替换为您有一个 RouteData 类的方法,其中只需包含一个字典。但是你失去了美丽的声明性做事方式。你选。

/// <summary>
/// This is your custom attribute type that you will use to annotate properties as route information.
/// </summary>
class RouteParamAttribute : Attribute
{
    public string RouteKey;
    public RouteParamAttribute(string routeKey)
    {
        RouteKey = routeKey;
    }
}

/// <summary>
/// From which all other routes inherit. This is optional and is used to avoid passing any kind of object to AddRoute.
/// </summary>
class Route
{

}

/// <summary>
/// This is an actual route class with properties annotated with RouteParam because they are route information pieces.
/// </summary>
class BlogRoute : Route
{
    [RouteParam("action")]
    public string Action { get; set; }
    [RouteParam("id")]
    public string ID { get; set; }
}

/// <summary>
/// This is all the reflection happen to add routes to your route system.
/// </summary>
/// <param name="routeInformation"></param>
void AddRoute(Route routeInformation)
{
    //Get the type of the routeInformation object that is passed. This will be used 
    //to get the route properties and then the attributes with which they are annotated.
    Type specificRouteType = routeInformation.GetType(); //not necessarily Route, could be BlogRoute.

    //The kind of attribute that a route property should have.
    Type attribType = typeof(RouteParamAttribute);

    //get the list of props marked with RouteParam (using attribType).
    var routeProperties = specificRouteType.GetProperties().Where(x => x.GetCustomAttributes(attribType, false).Count() >= 1);

    //this where we'll store the route data.
    Dictionary<string, string> routeData = new Dictionary<string, string>();

    //Add the data in each route property found to the dictionary
    foreach (PropertyInfo routeProperty in routeProperties)
    {
        //Get the attribute as an object (because in it we have the "action" or "id" or etc route key).
        var rpa = routeProperty.GetCustomAttributes(attribType, false).First() as RouteParamAttribute;

        //The value of the property, this is the value for the route key. For example if a property
        //has an attribute RouteParam("action") we would expect the value to be "blog" or "comments"
        var value = routeProperty.GetValue(routeInformation, null);

        //convert the value to string (or object depending on your needs, be careful 
        //that it must match the dictionary though)
        string stringValue = "";
        if (value != null)
            stringValue = value.ToString();
        else ; //throw an exception?

        routeData.Add(rpa.RouteKey, stringValue);
    }

    //now you have a dictionary of route keys (action, id, etc) and their values
    //manipulate and add them to the route system
}
于 2012-10-15T03:42:03.777 回答