我有一个Table类,它从其基类DbTableBase继承一个属性,并使用更具体的属性MegaList<DbColumnBase> Columns
隐藏基类属性MegaList<TableColumn> 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.
}
My Table类型有一个_columns字段,当它作为MegaList公开时,NVelocity无法迭代叶子Table.Columns列表:
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.Columns,但如果我的模板引用$ table.Columns2,则NVelocity会评估Table.Columns2。
我无法将属性设置为虚拟,因为类型不同,虽然是一个更具体的思考,我认为这种行为是因为VelocityContext持有&#34;对象&#34;引用,并且在倍数的情况下选择正确的属性存在某种问题,但我认为它应该选择叶属性。
答案 0 :(得分:1)
我无法重现您所看到的错误,如果有帮助,我已将下面的测试代码包含在内,但是......
如果您已捕获Visual Studio中打开的所有CLR异常,并且您在调试器下运行代码,那么您将看到NVelocity.Exception.ResourceNotFoundException
的一个常见原因是。如果异常消息指出它无法找到资源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; }
}
答案 1 :(得分:0)
我证明这是NVelocity中的错误/限制。我下载了NVelocity 1.1.0的源代码(Nuget的1.1.1版本),并链接到我的项目中并追溯到该问题。内省代码有点天真并且返回它找到的关于属性的第一件事,而不是检查是否有更好的候选者。使用.NET反射,可能存在具有相同名称但DeclaringType不同的类型的属性列表。特别是如果一个属性不是虚拟的,并且隐藏了一个基本属性,它必须检查propInfo.DeclaringType ==对象类型或者正确的OO是否在窗口之外。
我修补了NVelocity以正确使用C#继承的这一方面。我将通过代码库,看看还有什么可能需要解决这个问题。我希望在某个地方发布我的补丁版本,并希望改进文档。
对于NVelocity的文档有多么渺茫,以及工作或维护的证据很少,以及最新的源代码所在的位置,我感到困惑/困扰。我对这个项目以及其他项目缺乏运动感到非常沮丧,因为我有自己的商业产品,所以我可以为它自己分叉。