动态键入泛型类

本文关键字:泛型类 动态 | 更新日期: 2023-09-27 18:35:42

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

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

这序列化/反序列化我的 JSON 请求没有问题,一切都很好。 但是,我想在允许请求完成执行之前验证其中的一些信息,因此我添加了一个操作过滤器,用于检索 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并正确访问根目录,但它不允许这样做。 到目前为止,我只能使用以下方法获取所需的数据:

var notStrongEnough = arg.GetType().GetProperty("Info");
但是,我

宁愿不为此使用反射,如果没有答案,我很难前进。 在这种情况下,我的替代方法是将数据更改为字符串并手动序列化/反序列化 JSON 对象,但这违背了在 MVC3 上使用 Web API 的一些目的。

注意:将设计更改为将 SecureModel 作为基类会增加我对数据执行的一些哈希的挑战,因此我也不想走这条路。

谢谢!

编辑:标题措辞错误。

动态键入泛型类

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

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

现在,要获取信息,您可以简单地投射到ISecureModel .

就个人而言,我会选择创建单独的非类型化接口并实现它:

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

但是,您可以将 getter 和 setter 拆分为单独的接口,则可以使用 C# 模板协方差功能:

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