【问题标题】:Validation against the non generic attribute of a generic type针对泛型类型的非泛型属性进行验证
【发布时间】:2017-01-16 08:59:05
【问题描述】:

我想验证一个具有泛型属性的类:

class Foo
{
   [ValidHistoryDate]
   public MyType<string> bar;
   [ValidHistoryDate]
   public MyType<int> baz;
   [ValidHistoryDate]
   public MyType<float> bat;
}
class MyType<T>
{
   public string date;
   public T property;
}

泛型还包含一个日期,属性(字符串),应该根据有效日期进行验证,所以我编写了这个函数来做到这一点:

public class ValidHistoryDateAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value == null)
            return true;
        var v = (List<MyType<object>>)value;
        bool valid = true;
        foreach (var f in v)
        {
            if (!Regex.Match(f.Date, @"^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$").Success)
                valid = false;
        }
        return valid;
    }
}

验证不关心属性“property”,但它应该关心字符串。 不幸的是演员失败:

        var v = (List<MyType<object>>)value;

我的意思是:当然可以,因为“object”不是真正的类型。我想对所有类型使用验证属性,在验证中我什至不关心“属性”。

有什么方法可以很好地解决这个问题吗?我不想为每种可能的类型添加 ValidHistoryDateAttribute。

【问题讨论】:

  • 为什么将日期保存为字符串?如果您将其保留为 DateTime,则根本不需要此验证...
  • 你的类型 Foo 是否应该有 List&lt;MyType&lt;string&gt;&gt; 属性?否则,我对为什么您的验证属性在谈论列表感到困惑(鉴于这似乎是问题的核心,这似乎非常重要)。
  • 在不确定您的确切代码是什么的情况下,我可以暂时建议考虑一个基类,该基类上有您的字符串日期,然后由您的泛型类继承。这意味着您不需要知道您的类型的泛型类型,因为您可以从非泛型子类中获得所需的一切。如果您也可以将List&lt;GenericHistory&lt;T&gt;&gt; 更改为IEnumerable&lt;GenericHistory&lt;T&gt;&gt;,这可能有助于解决差异问题。
  • 另外,您的正则表达式将允许使用诸如55.77.9999 之类的字符串。使用DateTime.TryParseExact(),而不是正则表达式。

标签: c# .net validation .net-core


【解决方案1】:

如果我要这样做,我会在您的代码中添加一个非泛型基类型:

public class ValidatableObject
{
    public string date;
}

然后我的班级将是:

class MyType<T> : ValidatableObject
{
   public T property;
}

然后,您的验证代码将引用基类,这使事情变得更加简单。

看起来您实际上是在尝试投射 List&lt;GenerericHistory&lt;T&gt;&gt; 类型的东西,这会遇到方差问题。如果您假设您正在使用我的基类,则传入的项目不能轻易转换为List&lt;ValidatableObject&gt; - 看看为什么考虑实际列表应该只允许添加GenerericHistory&lt;T&gt;(其中 T 是特定类型)对象而 @ 987654326@ 将允许添加 any 类型的 GenerericHistory&lt;T&gt; 对象。因此不允许演员表。

如果您要将列表更改为IEnumerable&lt;GenerericHistory&lt;T&gt;&gt;,那么您将能够转换为IEnumerable&lt;ValidatableObject&gt;。原因是这次我们有一个只读对象,所以我们所做的只是获取ValidatableObject 类型的对象,并且因为知道实际的类只会返回GenerericHistory&lt;T&gt;(对于特定的T),我们也知道它总是返回ValidatableObject 类型,因此这次允许强制转换。

最后一点部分基于推测,因为您的代码似乎与代码中 List&lt;T&gt; 的使用不一致。我假设验证器是正确的,您的可验证对象上的属性是一个列表,但显然我不知道该列表是否可以更改,等等。

【讨论】:

  • 我只是简化了我的示例并将 GenericHistory 更改为“MyType”。你完美地回答了我的问题。惊人的。我真的很喜欢这个想法,它应该可以工作。
猜你喜欢
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 2017-12-31
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
相关资源
最近更新 更多