动态键入通用类

时间:2012-05-29 15:59:52

标签: c# asp.net-mvc

我有一个由WebAPI自动序列化的对象,但我想将其包装起来为我的数据提供上下文。一个例子是:

public class SecureModel<T>
{
  public string Info { get; set; }
  public T Data { get; set; }
}

这序列化/反序列化我的JSON请求没问题,一切都很好。但是,我想在允许请求完成执行之前验证一些Info,所以我添加了一个ActionFilter,我正在检索POST的参数。

public class MyAuth : System.Web.Http.Filters.ActionFilterAttribute
{
  public override void OnActionExecuting(HttpActionContext actionContext)
  {
    var arg = actionContext.ActionArguments.FirstOrDefault().Value;
    // arg: get the Info?
    // if the info isn't correct, return a specific Response.
  }
}

当我检查这个论点时,它正是我需要的,但是我无法弄清楚如何在没有指定实际泛型类型的情况下弱化它到SecureModel。我觉得我应该能够将其置于SecureModel&lt; object&gt;并正确访问root,但它不允许这样做。到目前为止,我只能使用我需要的数据:

var notStrongEnough = arg.GetType().GetProperty("Info");

但是,我宁愿不使用反射,我也很难在没有答案的情况下前进。在这种情况下,我的替代方法是将Data更改为字符串并手动序列化/反序列化JSON对象,但这会破坏使用Web API而不是MVC3的一些目的。

注意:更改设计以使SecureModel成为基类会增加我在数据上执行的一些哈希的挑战,所以我不想走这条路。< / p>

谢谢!

修改:错位标题。

2 个答案:

答案 0 :(得分:3)

C#中此类问题的典型解决方案是创建泛型类型实现的非泛型接口。例如,与您的班级:

public class SecureModel<T>
{
    public string Info { get; set; }
    public T Data { get; set; }
}

您可以定义一个界面ISecureModel

public interface ISecureModel 
{
    string Info { get; }
    object Data { get; }
}

现在您可以在数据类中实现它:

public class SecureModel<T> : ISecureModel
{
    public string Info { get; set; }
    public T Data { get; set; }

    object ISecureModel.Data {
        get { return Data; }
    }
}

我们在这里使用显式接口实现,因为属性object的非泛型(T)和泛型(Data)版本会发生冲突。

现在,要获取信息,您只需转发到ISecureModel

答案 1 :(得分:1)

我个人会选择创建单独的无类型接口并实现它:

interface IObjectTypeSercureModel
{
    object GetData();
    string GetInfo();
}

但是,您可以将getter和setter拆分为单独的界面,可以使用C#template co-variance功能:

public interface IReadModel<out T>
{
    T Data {get;}
    string Info { get; }
}
public interface IWriteModel<in T>
{
    T Data { set; }
    string Info { set; }
}
public class SecureModel<T> : IReadModel<T>, IWriteModel<T>
{
    public string Info { get; set; }
    public T Data { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var m = new SecureModel<string>();
        m.Data = "test";

        IReadModel<object> genericRead = (IReadModel<object>)m;
        Console.WriteLine(genericRead.Data);
    }
}