【问题标题】:Retrieving subclass type in base class?检索基类中的子类类型?
【发布时间】:2011-01-14 00:32:11
【问题描述】:

我正在尝试使用 Microsoft 企业验证方法在我的实体中执行验证。在我的基类中,我有以下方法:

public class BaseEntity
{
  public bool IsValid()
  {
     return Validate().IsValid;
  }

  public ValidationResults Validate()
  {
     return Validation.Validate<this.GetType()>(this);
}

这样做的问题是,即使 BaseEntity 的子类调用 IsValid,this.GetType() 总是返回 BaseEntity,而不是子类的类型。我不想为每个实体重写这段代码,因为这看起来很不像 OO。有没有其他方法可以做到这一点?

我确实有想法让受保护的变量 protected Type _validationType,并在每个实体中将其设置为该实体的 .GetType 值,但似乎必须有更好的方法来做到这一点。

更新
显然没关系。 this.GetType() 似乎像我希望的那样工作。不知道为什么以前没有。

我还更改了我的 Validate() 方法以使用以下代码:

 return ValidationFactory.CreateValidator(this.GetType()).Validate(this);

【问题讨论】:

    标签: c# validation inheritance subclass


    【解决方案1】:

    当您使用 O/RM 映射器(例如 LINQ to SQL、NHibernate 或 LINQ to Entities(ADO.NET 实体框架))时,我会采用另一种验证方法。我会保持实体完全没有验证(所以没有 BaseEntity.Validate() 在那里。您可以将此验证逻辑移动到 ObjectContext (EF) / DataContext (L2S) / Session (NH) 并在数据库提交期间触发验证. 看下面 LINQ to SQL 的例子:

    public partial class NorthwindDataContext
    {
        public override void SubmitChanges(ConflictMode failureMode)
        {
            var invalidResults = (
                from entity in this.GetChangedEntities()
                let type = entity.GetType()
                let validator = ValidationFactory.CreateValidator(type)
                let results = validator.Validate(entity)
                where !results.IsValid
                from result in results
                select result).ToArray();            
    
            if (invalidResults.Length > 0)
            {
                // You should define this exception type
                throw new ValidationException(invalidResults);
            }
    
            base.SubmitChanges(failureMode);
        }
    
        private IEnumerable<object> GetChangedEntities()
        {
            ChangeSet changes = this.GetChangeSet();
            return changes.Inserts.Concat(changes.Updates);
        }
    }
    

    如果您的实体无效,将抛出 ValidationException。您可以捕获该特定异常并迭代您在其上定义的 InvalidResults 属性。

    当您需要更多信息时,我建议您阅读this 文章。它还描述了如何使用 Entity Framework 执行此操作。

    祝你好运。

    【讨论】:

    • 我真的很喜欢这个。我最初不喜欢在实体本身中进行验证,但我能想出或找到的唯一其他解决方案是在我的 nhibernate 类和我的实体之间创建一个非常薄的层(我对此不满意)。这实际上解决了很多问题,尤其是当用于我发现的 nhibernate 验证器的东西时(由于这篇文章)。谢谢!
    • @KallDrexx:很高兴你喜欢它。我从未在 NHibernate 上测试过它是如何工作的,所以欢迎任何这样的例子。
    • 我见过一些例子,主要是使用 nhibernate 验证库(并使用 xval 作为抽象层)。我还没有仔细研究示例,因为首先我将研究在我的应用程序中实现 xval,然后从那里我将研究将 nhibernate 连接到它(我看到的一切就像告诉验证库一样简单将其处理程序挂钩到 ISession)。
    【解决方案2】:

    除了关于验证的所有内容之外,还有一种方法可以编写一个基类的方法,让它知道调用它的实际子类类型。

    嗯……至少是一种假装的方式(不违反任何OO 规则,Gabriel)。它非常优雅,效果很好:

    public ValidationResults Validate<TEntity>(this TEntity e) where TEntity : BaseEntity
    {
       return Validation.Validate<TEntity>(e);
    }
    

    扩展方法的一大好处... :)

    【讨论】:

      【解决方案3】:

      将类型逻辑移出 BaseEntity 更简洁。

      public class BaseEntity
      {
          public bool IsValid()
          {
              return Validate().IsValid;
          }
      
          public ValidationResults Validate()
          {
              return Validation.Validate(this);
          }
      }
      public class Validation
      {
          public static ValidatorResults Validator<T>( T entity )
              where T : BaseEntity
          {
              return ValidationFactory.CreateValidator(entity.GetType()).Validate(entity);
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以将IsValid()Validate() 设为虚拟方法,以便在子类中提供一些自定义定义。

        【讨论】:

          【解决方案5】:

          very un-OO like 让基类了解有关子类的任何信息。这就是它应该工作的方式。

          如果你想知道一些关于子类的事情,那么你需要重写这个方法。

          【讨论】:

            猜你喜欢
            • 2016-06-18
            • 1970-01-01
            • 2022-01-03
            • 2021-07-07
            • 1970-01-01
            • 2014-03-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多