【发布时间】:2013-03-29 17:53:15
【问题描述】:
假设我有一个通用的List<ICalculation>,它用作我的应用程序中所有预定义计算的存储库...
我有一个名为ICalculation<T, U> 的通用接口,它实现了更基本的ICalculation。
public interface ICalculation
{
string Identifier { get; }
object Calculate(object inputData);
}
public interface ICalculation<in TIn, out TOut> : ICalculation
{
string Identifier { get; }
TOut Calculate(TIn inputData)
}
我还有一个抽象类 CalculationBase 实现了这个接口
public abstract class CalculationBase<TIn, TOut> : ICalculation<in TIn, out TOut>, ICalculation
{
public abstract string Identifier { get; }
public abstract Func<TIn, TOut> Calculation { get; }
public virtual TOut Calculate(TIn inputData)
{
return Calculate(inputData, Calculation);
}
virtual object ICalculation.Calculate(object inputData)
{
return (TOut)calculation((TIn)inputData);
}
public static TOut Calculate(TIn inputData, Func<TIn, TOut> calculation)
{
if (calculation == null || inputData == null)
return default(TOut);
return calculation(inputData);
}
}
所以,现在我有了一大堆计算,它们通过一些输入实现了 CalculationBase 函数……一个例子:
public sealed class NumberOfBillableInvoices : CalculationBase<IClientAccount, int>
{
public override string identifier { get { return "@BillableInvoiceCount"; } }
public override Func<IClientAccount, int> Calculation
{
get { return inputData => inputData.Invoices.Count(i => i.IsBillable); }
}
}
每个计算都针对特定类型的对象,并根据计算的性质返回不同的输出。例如:货币计算可能返回小数,计数器可能返回整数或长整数等。
我有一个计算存储库,它会在应用程序负载时自行加载,当需要计算公式时,计算引擎会获取正在查询的对象 - 在本例中,如果我们有一些具体实例IClientAccount 类型的,我们希望针对它评估一些公式 - 例如,对前 5 张之后的每张发票征收 1.20 美元:"Math.Max(@BillableInvoiceCount - 5, 0) * $1.20"。引擎会抓取所有 TIn 类型为 IClientAccount 的计算,并将计算与公式中找到的令牌匹配(即@BillableInvoiceCount)。然后一些计算引擎,如 NCalc、FLEE 或其他计算引擎将评估最终方程。
所以,我的问题是我不希望遍历 每个 计算以寻找正确的标记 - 实际上,如果标记跨越多个对象类型,它们可能会发生冲突。例如,我可能想在不同的上下文中使用相同的标记来表示不同的事物。如果我可以将存储库中的计算范围缩小到 TIn 与我尝试计算的对象类型匹配的那些,那会更容易。
在这一点上我有一些想法-
1)。我可以创建一个仅编组对象的 TIn 部分的存储库吗?我认为这个问题的答案很可能,不......但如果有可能,我不知道如何实现这一点 - 有没有人有任何想法?
2)。有没有办法在我的存储库中查询 TIn 与我正在查询的对象的类型匹配的所有计算?如果有,怎么做?
3)。我是否有多个存储库基于我计算的所有 TIn/TOut 组合...如果是这样,我如何将正确的存储库与我正在查询的对象结合起来?因为我仍在尝试仅根据 TIn 部分匹配存储库...
4)。让我的所有计算都返回双精度而不是让它们返回不同的类型,然后我的存储库可以输入到输入类型,从而使它们更简单......但是虽然这很简单,但从语义上来说,它只是感觉不对。
想法?
提前干杯:)
【问题讨论】:
-
考虑使用小数而不是双精度数进行货币计算。对长度或质量等物理量使用双精度数。
-
谢谢埃里克...也许我对货币的引用应该是小数...现在我想起来了,我的代码库中的类实际上使用小数作为货币 - 我更正了我的引用,谢谢; )
标签: c# generics .net-4.0 covariance contravariance