当派生类中存在新属性时,请选择基类属性

本文关键字:属性 基类 请选择 派生 存在 新属性 | 更新日期: 2023-09-27 17:58:56

我有一个Table类,它从基类DbTableBase继承了一个属性,并用更具体的属性MegaList<TableColumn> Columns隐藏基类属性MegaList<DbColumnBase> Columns

最初,我的应用程序只针对Oracle,但最近对一个公共基础进行了重构,以便添加SQLServer和其他目标,导致Velocity模板失败。我的NVelocity模板模块在任何具有被派生隐藏的基本实现的集合上都失败了,因为它评估了基本属性。

  context.Put("table", table);  // table is Table, not TableBase
  ...
  #foreach ($c in $table.Columns)
  $c.Name
  #end

我的集装箱报关单是:

 public class MegaList<T> : ObservableCollection<T>
 {
     public MegaList() {} 
     // etc. etc.
 }

我的表类型是有一个_columns字段,当它作为MegaList公开时,NVelocity无法迭代叶表。列列表:

public class Table : TableBase {
   MegaList<ColumnBase> _columns = new MegaList<ColumnBase>();
   public MegaList<ColumnBase> Columns   // template takes this one, even though it is hidden
   {
       get { return _columns; }
   }
}
public class Table : TableBase {
   new public MegaList<TableColumn> Columns   // Velocity ignores this, chooses base Columns
   {
      get { return _columns.DownCast<TableColumn>(); }
      set { _columns = value.UpCast<DbTableColumn, TableColumn>(); }
   }
   public MegaList<TableColumn> Columns2  // Velocity sees this 
   {
       get { return _columns;  }   
   }
 }

NVelocity正在评估基本TableBase。列,但是如果我的模板引用$table。第2列,NVelocity评估表。第2.列

我不能使属性成为虚拟的,因为类型不同,尽管更具体。大声思考,我认为这种行为是因为VelocityContext持有"对象"引用,并且在倍数的情况下选择正确的属性有某种问题,尽管我认为它应该选择叶属性。

当派生类中存在新属性时,请选择基类属性

我无法重现您看到的错误,如果有帮助的话,我在下面包含了我的测试代码,但是。。。

看到NVelocity.Exception.ResourceNotFoundException的一个常见原因是,如果在Visual Studio中打开了catch all CLR异常,并且在调试器下运行代码。如果异常消息表示找不到资源VM_global_library.vm,则这是一个无害的异常,NVelocity正在尝试加载全局宏的可选资源文件。因为NVelocity是Java Velocity的一个端口,所以异常通常用于Java库中的控制流。

[Test]
public void CustomObservableCollectionT()
{
    VelocityEngine velocityEngine = new VelocityEngine();
    velocityEngine.Init();
    Table table = new Table();
    table.Columns.Add(new TableColumn { Name = "Full Name" });
    table.Columns.Add(new TableColumn { Name = "Email Address" });
    table.Columns.Add(new TableColumn { Name = "DOB" });
    VelocityContext context = new VelocityContext();
    context.Put("table", table);
    using (StringWriter sw = new StringWriter())
    {
        velocityEngine.Evaluate(context, sw, "",
            "#foreach ($c in $table.Columns)'r'n" +
            "$c.Name'r'n" +
            "#end"
        );
        Assert.AreEqual(
            "Full Name'r'n" +
            "Email Address'r'n" +
            "DOB'r'n",
            sw.ToString());
    }
}
public class MegaList<T> : ObservableCollection<T>
{
}
public class Table
{
    private readonly MegaList<TableColumn> _columns = new MegaList<TableColumn>();
    public MegaList<TableColumn> Columns
    {
        get { return _columns; }
    }
    public List<TableColumn> ColumnList
    {
        get { return _columns.ToList(); }
    }
    public ObservableCollection<TableColumn> ColumnCollection
    {
        get { return new ObservableCollection<TableColumn>(_columns); }
    }
}
public class TableColumn
{
    public string Name { get; set; }
}

我证明了这是NVelocity中的一个错误/限制。我下载了NVelocity 1.1.0的源代码(1.1.1来自Nuget?),并链接到我的项目中,并追踪到问题所在。内省代码有点天真,它返回它发现的关于属性的第一件事,而不是检查是否有更好的候选者。具有NET反射,可能存在具有相同名称但DeclaringType不同的类型的属性列表。特别是如果一个属性不是虚拟的,并且隐藏了一个基本属性,则必须检查propInfo。DeclaringType==对象的类型或正确的OO不在窗口中。

我修补了NVelocity以正确处理C#继承的这一方面。我将浏览代码库,看看还有什么需要解决的问题。我将在某个地方发布我的补丁版本,并改进文档。

我感到困惑/困扰的是,关于NVelocity的文档是多么的稀少,工作或维护的证据是多么的少,也没有最新的源代码在哪里。我对这个项目和其他项目缺乏进展感到非常沮丧,我可能会为了自己的利益而放弃它,因为我有依赖它的商业产品。