首先,我按照本教程创建了Money对象:https://www.codeproject.com/articles/837791/money-pattern
Money totalItems = _invoice.InvoiceDetails
.Sum(y => y.Amount); // Amount is of type Money
我在y.Amount
上收到了编译异常:
无法隐式转换类型 '钱'长期?'不能 将lambda表达式转换为预期的委托类型,因为有些 块中的返回类型不能隐式转换为 委托返回类型
我做错了什么?
这是我的Money课程:
public class Money
{
public decimal Amount { get; private set; }
public CurrencyCode Currency { get; private set; }
#region Constructors
public Money() { }
public Money(Money amount)
{
this.Amount = amount.Amount;
this.Currency = amount.Currency;
}
public Money(decimal amount, CurrencyCode currencyCode)
{
this.Amount = amount;
this.Currency = currencyCode;
}
public Money(int amount, CurrencyCode currency)
: this(Convert.ToDecimal(amount), currency)
{
}
public Money(double amount, CurrencyCode currency)
: this(Convert.ToDecimal(amount), currency)
{
}
#endregion
#region Comprasion operators
public static bool operator ==(Money var1, Money var2)
{
if ((object)var1 == null || (object)var2 == null)
return false;
if (var1.Currency != var2.Currency) return false;
return var1.Amount == var2.Amount;
}
public static bool operator !=(Money var1, Money var2)
{
return !(var1 == var2);
}
public static bool operator >(Money var1, Money var2)
{
if (var1.Currency != var2.Currency)
throw new InvalidOperationException("Comprasion between different currencies is not allowed.");
return var1.Amount > var2.Amount;
}
public static bool operator <(Money var1, Money var2)
{
if (var1 == var2) return false;
return !(var1 > var2);
}
public static bool operator <=(Money var1, Money var2)
{
if (var1 < var2 || var1 == var2) return true;
return false;
}
public static bool operator >=(Money var1, Money var2)
{
if (var1 > var2 || var1 == var2) return true;
return false;
}
#endregion
#region Ariphmetical operations
public static Money operator +(Money var1, Money var2)
{
if (var1.Currency != var2.Currency)
{
throw new InvalidCastException("Calculation is using different currencies!");
}
return new Money(var1.Amount + var2.Amount, var1.Currency);
}
public static Money operator -(Money var1, Money var2)
{
if (var1.Currency != var2.Currency)
{
throw new InvalidCastException("Calculation is using different currencies!");
}
return new Money(var1.Amount - var2.Amount, var1.Currency);
}
public static Money operator *(Money var1, Money var2)
{
if (var1.Currency != var2.Currency)
{
throw new InvalidCastException("Calculation is using different currencies!");
}
return new Money(var1.Amount * var2.Amount, var1.Currency);
}
public static Money operator /(Money var1, Money var2)
{
if (var1.Currency != var2.Currency)
{
throw new InvalidCastException("Calculation is using different currencies!");
}
return new Money(var1.Amount / var2.Amount, var1.Currency);
}
public static Money operator *(decimal var1, Money var2)
{
return new Money(var1 * var2.Amount, var2.Currency);
}
public static Money operator *(Money var1, decimal var2)
{
return new Money(var1.Amount * var2, var1.Currency);
}
public static Money operator /(decimal var1, Money var2)
{
return new Money(var1 / var2.Amount, var2.Currency);
}
public static Money operator /(Money var1, decimal var2)
{
return new Money(var1.Amount / var2, var1.Currency);
}
public static Money operator *(int var1, Money var2)
{
return new Money(var1 * var2.Amount, var2.Currency);
}
public static Money operator *(Money var1, int var2)
{
return new Money(var1.Amount * var2, var1.Currency);
}
public static Money operator /(int var1, Money var2)
{
return new Money(var1 / var2.Amount, var2.Currency);
}
public static Money operator /(Money var1, int var2)
{
return new Money(var1.Amount / var2, var1.Currency);
}
public static Money operator *(long var1, Money var2)
{
return new Money(var1 * var2.Amount, var2.Currency);
}
public static Money operator *(Money var1, long var2)
{
return new Money(var1.Amount * var2, var1.Currency);
}
public static Money operator /(long var1, Money var2)
{
return new Money(var1 / var2.Amount, var2.Currency);
}
public static Money operator /(Money var1, long var2)
{
return new Money(var1.Amount / var2, var1.Currency);
}
#endregion
public override bool Equals(object obj)
{
if (obj == null) return false;
Money money = obj as Money;
return (this.Amount == money.Amount && this.Currency == money.Currency);
}
public bool Equals(Money money)
{
if ((object)money == null) return false;
return (this.Amount == money.Amount && this.Currency == money.Currency);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override string ToString()
{
return this.Amount.ToString();
}
#endregion
答案 0 :(得分:4)
据推测,InvoiceDetails
是包含public Money Amount
属性的类的集合,例如:
public class InvoiceDetail
{
public Money Amount { get; set; }
}
在这种情况下,您可以使用Enumerable.Aggregate()
来完成总和:
var sum = InvoiceDetails.Aggregate(new Money(0, InvoiceDetails.First().Amount.Currency), (s, d) => s + d.Amount);
要摆脱稍微丑陋的new Money(0, InvoiceDetails.First().Amount.Currency)
表达式,您可能需要引入一个不包含任何金钱的特殊单身Money.Empty
,并且可以添加到任何类型的资金中。或者修改静态运算符以接受null
的{{1}}值并执行:
Money
或者,引入中间var sum = InvoiceDetails.Aggregate((Money)null, (s, d) => s + d.Amount);
可能会使表达式更清晰:
Select()
Enumerable.Sum()
不起作用的原因是它是为一组固定的可枚举算术类型定义的。对于已引入算术运算符重载的任意类型,没有var sum = InvoiceDetails.Select(d => d.Amount).Aggregate((s, a) => s + a);
,因为此类场景没有通用接口或类型推断。 (请参阅Is there a constraint that restricts my generic method to numeric types?,答案是"no"。)当然,您可以添加自己的Sum()
版本,该版本支持提供自己算术运算的类型,例如, this answer是一个可以开始的地方。
答案 1 :(得分:1)
与@ dbc的回答类似。您需要创建自己的Sum
方法的具体示例。这是因为operator
是静态的,而不是可接口的。
我实际上会与dbc略有不同,因为
Enumerable.First()
的使用会导致IEnumerable
Enumerable.First()
会失败,但会产生一个不好的例外。相反,我更喜欢。
namespace System.Linq //Using System.Linq namespace makes it easier to use
{
public static class MoneyEnumerable
{
public static Money Sum(this IEnumerable<Money> monies)
{
return monies.Aggregate((left, right) => left + right);
}
}
}
答案 2 :(得分:1)
我最近通过以下两种扩展方法解决了类似的问题。
public static Money Sum<T>(this IEnumerable<T> source, Func<T, Money> selector)
=> Sum(source.Select(selector));
public static Money Sum(this IEnumerable<Money> money)
=> money.Aggregate((left, right) => left + right);
答案 3 :(得分:0)
您可以添加一个隐式运算符,允许将对象转换为可以求和的类型。
public static implicit operator decimal(Money money) {
return money != null ? money.Amount : 0;
}