- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试创建一个简单的报告工具,用户可以在其中从一组 KPI、图表、聚合函数和其他参数中进行选择,单击一个按钮,然后调用 wcf 服务,然后返回自定义包含所有数据的模型。然后这可以显示在 MVC/WPF 应用程序中(可以是两者)。
由于用户可能来自多个国家/地区,我想使用数据注释以适合当前用户习惯的语言和数字格式的方式描绘所有数字和标题。
数据加载和所有相关工作正常,没有任何问题。此外,我使用数据注释,因此所有特定于语言/文化的设置都得到了照顾。当我尝试将所有数据放入要显示给用户的模型时,问题就开始了。
我想要做的是拥有一个包含列集合的 Report 类。每列可以是 int/double/... 值的列表。现在,由于我正在处理 WCF,并且上面的解释暗示(据我所知)泛型的使用,我假设我可以将 [KnownType] 或 [ServiceKnownType] 用于类/wcf 操作,而实际上使用基类型或接口(interface)作为返回值。从来没有真正尝试过这个,但我发现了一些对我来说似乎很合乎逻辑的很好的解释,所以我认为这部分不会有任何大问题(至少我希望不会)。
现在,我的界面是这样的(经过简化以专注于我遇到的实际问题):
public interface IReport<T> where T: IConvertible { ICollection<IColumn<T>> Columns { get; set; } }
public interface IColumn<T> where T: IConvertible { ICollection<IValue<T>> Values { get; set; } }
public interface IValue<T> where T: IConvertible { T Value { get; set; } }
因为每一列中的值都可以是 int/double/...,我假设我必须有一个实际的类来表示值(我不认为我可以在集合类型上使用数据注释属性) ,因此:
public class IntValue: IValue<int>
{
[DisplayFormat(DataFormatString = "{0:#,##0;-#,##0;'---'}", ApplyFormatInEditMode = true)]
public int Value { get; set; }
}
当然,这看起来很奇怪,因为您可以将它设为实现 IValue 的通用类 Value 并完成它,但是如果我做了愚蠢的事情并为每种可能的类型创建一个类(现在我输入它out,这听起来很糟糕,我知道),我可以使用 DisplayFormat 属性,而不必担心它向用户展示自己的方式,它总是合适的。
现在,对于实现 IColumn 和 IReport 的类来说,这很简单:
public class Report<T>: IReport<T> where T: IConvertible
{
public ICollection<IColumn<T>> Columns { get; set; }
public Report() { Columns=new List<IColumn<T>>(); }
}
public class Column<T>: IColumn<T> where T: IConvertible
{
public ICollection<IValue<T>> Values { get; set; }
public Column() { Values = new List<IValue<T>>(); }
}
从接口(interface)和类的列表中,您会立即看到,这使得无法生成某些列具有其他类型的报告。因此,不可能创建一个报告,其中某些列是 int,有些是 double,......由于 IReport 中的通用约束使您指定一个类型,因此您对所有列都坚持使用该类型,因为它向下传播到值每列...这正是我真正想要的。
我觉得我没有取得任何进展,并且可能遗漏了一些非常简单的东西,因此不胜感激向正确的方向推进。
TL;DR:如何获得非泛型类型的泛型集合?
最佳答案
好吧,我从建议的解决方案中获得灵感并实现了如下变体。我知道不想过多地使用泛型,但它仍然让我很恼火。毕竟,我想要多种类型的列(或值)。这就是泛型的用途。此外,我想提供一种内置机制来提供字段格式。
我保留了 IReport 和 IColumn 接口(interface)非常简单,但我没有在 IColumn 接口(interface)中引用 IValue 接口(interface)。相反,我使用了一个抽象类 Value,在其中定义了一些用于格式化和数据检索(即字符串格式)的基本框架。
在实际的 IntValue/DoubleValue 和 Value 基类之间,我添加了一个通用的 Value 类,它实现了通用的 IValue 接口(interface),除了提供 Data 字段外什么都不做,所以我不必在 IntValue/DoubleValue 中这样做类,并实现 AsFormattedString 方法,该方法使用普通的 ToString 方法,使用我在 Value 基类构造函数中创建的 Formatter。
该格式化程序的实际实现在 IntValue/DoubleValue 类中提供,并提供了使用我已经硬编码的标准格式或类用户提供的自定义格式的可能性。
public interface IReport { ICollection<IColumn> Columns { get; set; } }
public interface IColumn { ICollection<Value> Values { get; set; } }
public interface IValue<T> where T: IConvertible { T Data { get; set; } }
public abstract class Value
{
#region Formatting
protected IFormatProvider Formatter { get; set; }
protected abstract IFormatProvider GetFormatter();
protected abstract string AsFormattedString();
public override string ToString() { return AsFormattedString(); }
#endregion
public Value() { Formatter = GetFormatter(); }
}
public abstract class Value<T>: Value, IValue<T> where T: IConvertible
{
#region IValue members
public T Data { get; set; }
#endregion
#region Formatting
protected override string AsFormattedString() { return Data.ToString(Formatter); }
#endregion
}
public class IntValue: Value<int>
{
public IntValue() { }
public IntValue(string formatstring, int data) { Formatter = new IntFormatter(formatstring); Data = data; }
#region Formatting
protected override IFormatProvider GetFormatter() { return new IntFormatter(); }
internal class IntFormatter: CustomFormatter
{
public IntFormatter() : this("{0:#,##0;-#,##0;'---'}") { }
public IntFormatter(string formatstring) : base(formatstring) { }
}
#endregion
}
public class DoubleValue: Value<double>
{
public DoubleValue() { }
public DoubleValue(string formatstring, double data) { Formatter = new DoubleFormatter(formatstring); Data = data; }
#region Formatting
protected override IFormatProvider GetFormatter() { return new DoubleFormatter(); }
internal class DoubleFormatter: CustomFormatter
{
public DoubleFormatter() : this("{0:0.#0;-0.#0;'---'}") { }
public DoubleFormatter(string formatstring) : base(formatstring) { }
}
#endregion
}
public class ReportView: IReport
{
public ICollection<IColumn> Columns { get; set; }
public ReportView() { Columns = new List<IColumn>(); }
}
public class ReportColumn: IColumn
{
public ICollection<Value> Values { get; set; }
public ReportColumn() { Values = new List<Value>(); }
}
它是这样使用的:
// Creating a report
IReport report = new ReportView();
// Adding columns
IColumn mycolumn = new ReportColumn();
mycolumn.Values.Add(new IntValue() { Data = 1 });
mycolumn.Values.Add(new DoubleValue() { Data = 2.7 });
mycolumn.Values.Add(new IntValue("{0:#,##0;-#,##0;'---'}", 15));
mycolumn.Values.Add(new DoubleValue("{0:0.#0;-0.#0;'---'}", 2.9));
report.Columns.Add(mycolumn);
// Looping through each column, and get each value in the formatted form
foreach(var column in report.Columns)
{
foreach(var value in column.Values) { value.ToString(); }
}
如果有什么需要添加/更正的,我很乐意听到。我将检查上面由 Binary Worrier 暗示的访客模式,并测试整个设置。如果我做出愚蠢或糟糕的设计选择,请告诉我!我可能需要稍微左右修改一下,以便为整个列提供一种单一格式,而不必为每个值提供它,但我认为基本框架就在那里。
关于c# - 半临时报告的通用接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34593222/
编写一个仅用于集中其他接口(interface)的接口(interface)是好的做法还是坏的做法? interface InterfaceA : InterfaceB, InterfaceC { }
有没有一种方法可以确定具体类型从任意接口(interface)列表?我知道类型转换,但我想知道所有满意的接口(interface)。 例如,给定: type Mover interface { Mo
我正在尝试制作斐波那契堆。 (在我正在上的算法课中多次提到它们,我想检查一下。)我希望堆使用任何类型的节点,所以我定义了一个 Node 接口(interface): package node type
这是我的代码: type IA interface { FB() IB } type IB interface { Bar() string } type A struct {
示例 A: // pseudo code interface IFoo { void bar(); } class FooPlatformA : IFoo { void bar() {
合并它编译的 leppies 反馈 - 但 IMO 有一些缺点,我希望编译器强制每个子类定义它们自己的 Uri 属性。现在的代码: [] type UriUserControl() = inh
我正在构建一个项目,该项目从用户那里获取一个术语,然后执行谷歌搜索并返回一个 json 格式的标题列表。 我正在使用 serpwow API 来执行谷歌搜索并试图解析响应。 但是我收到的错误是: pa
我只想在其他接口(interface)中实现某些接口(interface),我不希望它们能够被类直接继承。 提前致谢! 最佳答案 您不能在 C# 中执行此操作 - 任何类都可以实现它有权访问的任何接口
我是 Go 的新手,还有一些我还没有掌握的技巧 例如,我有一个可以这样调用的函数: myVar.InitOperation("foo",Operator.EQUAL,"bar") myVar.Init
我有一个通用接口(interface)来描述对输出流的访问,如下所示: interface IOutput { function writeInteger(aValue:Int):Void;
我正在做一个项目,我想通过某种接口(interface)(最好是 USB)将光电探测器电路安装到计算机上。但是,由于我是新手,所以我不知道应该朝哪个方向处理这个问题。假设我有一个带有 USB 连接的光
背景 我正在尝试创建一个简单的应用程序,以真正理解DDD + TDD + etc的整个堆栈。我的目标是在运行时动态注入DAL存储库类。这让我 域和应用程序服务层可测试。我打算用“穷人的DI”来完成 现
在 Java 中,接口(interface)扩展接口(interface)是完全合法的。 UML 中的这种关系看起来像“扩展”关系(实线、闭合、未填充的箭头)还是“实现”关系(虚线、闭合、未填充的箭头
我想创建一个具有相等和比较函数默认实现的接口(interface)。 如果我从类型 IKeyable 中删除所有内容除了Key成员,只要我不添加默认实现,它就是一个有效的接口(interface)。从
COM 中的双接口(interface)是能够通过 DispInterface 或 VTable 方法访问的接口(interface)。 现在有人可以告诉我这两种方法之间到底有什么区别吗? 我认为 V
我有一个类方法,它返回一个可以迭代的员工列表。返回列表的最佳方式是什么?通常我只返回一个 ArrayList。然而,据我了解,界面更适合这种类型的操作。哪个是最好使用的界面?另外,为什么返回接口(in
我想从包装类外部实例化一个内部非静态接口(interface)。 这可能吗? 考虑以下代码: shared class AOuterClass() { Integer val = 3; shared
我为一个类编写了一个接口(interface),如下所示: public interface IGenericMultipleRepository { Lazy> addresses { ge
我是 UML 的初学者,现在我正在创建一个序列图,问题是我想根据用户输入实现 DAO 接口(interface)。如何在时序图中正确绘制以实现接口(interface)。 最佳答案 您不会在 SD 上
要使用 jsr 303 验证创建有条件验证的组,请将接口(interface)类传递给注释,如下所示: @NotEmpty (groups={UpdateValue.class}) 我有很多不同的接口
我是一名优秀的程序员,十分优秀!