2016-12-16 33 views
5

kısa:
decimal GetAmount(IThing thing) yöntemim var. things.Sum(GetAmount) kullanımı bir CS0121 hatasıyla sonuçlanır: çağrı Sum(Func<T, int>) ve Sum(Func<T, int?>) arasında belirsizdir. Niye ya?Neden int ve int arasında belirsiz ondalıklı Linq.Sum()?

uzun:

public interface IThing { } 
public class Sample { 
    public decimal GetAmount(IThing thing) { return 0; } 
    public decimal Total(IThing[] things) { return things.Sum(GetAmount); } 
} 

Error CS0121 The call is ambiguous between the following methods or properties: 'Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, int>)' and 'Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, int?>)'

derleyici decimal ve decimal? arasında veya derleyici birçok Sum aşırı herhangi Açamadığım eğer karıştı eğer biraz anlayacaklardır. Ama neden/o yardımsever 'sadece int ve

int? Btw, VS/R # kendisini sınırlamak vermedi nasıl bir hata olarak .Sum() için GetAmount geçen vurgular ve bunun yerine yöntemi dönen bir int geçen öneriyor. Derleyici bu kısmı ikinci bir hata olarak işaretlemiyor. GetAmount'un int GetAmount(IThing thing)'a değiştirilmesi aslında derleyici hatasını 'çözer'.

ps. Derleyici hatasına bir çözüm aramıyorum. Biliyorum GetAmount'u Func<IThing, decimal> GetAmount { get; }'a çevirebilirim veya Total gibi things.Sum(thing => GetAmount(thing))'u uygulayabilirim. Ve @IvanStoev tarafından önerildiği gibi, things.Sum(new Func<IThing, decimal>(GetAmount)) da (benim için) çalışır.

+1

Bunun nedeni, derleyicinin yalnızca dönüş türü nedeniyle yöntemleri bırakamamasıdır. Bununla birlikte, derleyicinin * tek bir yöntem olduğu gibi ayırt etmesinin bile * neden ihtiyaç duyduğunu merak ediyorum. İyi soru olsa da. – HimBromBeere

+0

Int'nin nereden geldiğini bilmiyorum, ancak [ondalıklarla hata alıyorum] (https://dotnetfiddle.net/ZoCY2G) – Reniuz

+1

@mybirthname Bu, hangi sonuca ulaşmak için benzersiz bir yöntem olduğu sürece çalışır * OP'ler durumunda. – HimBromBeere

cevap

4

Yalnızca yönteminizi geçirebileceğiniz .Sum() aşırı yüklenme yok.

Haklısınız bunu bu şekilde yapabilirsiniz:

things.Sum(thing => GetAmount(thing)) 

thing => GetAmount(thing)

- Bu bölüm temelde anonymouse işlevi oluşturun ve .Sum() bunun için aşırı aldık. Bunu uygulamak için diğer yollardan

One (daha obviouse yolu ne aslında happends anlayabilmeleri) Kendine fonk yaratmaktır:

public decimal Total(IThing[] things) 
{ 
    return things.Sum(new Func<IThing, decimal>(GetAmount)); 
} 

Aslında ben senin koduyla başka derleyici hatası alıyorum (I 2015 VS kullanmak).

Severity Code Description Project File Line Suppression State Error CS0407 'decimal Sample.GetAmount(IThing)' has the wrong return type

Bu yüzden sadece precompiler analizörü nedeniyle bu derste kablolu hata mükemmel olmadığını olsun düşünüyorum.

ben biraz daha araştırma yaptım ve bunun gibi komut isteminden precompiler olmadan kodunuzu derlemeye deneyin: Eğer Şimdi gördüğümüz gibi

Program.cs(13,56): error CS0121: The call is ambiguous between the following methods or properties: 'System.Linq.Enumerable.Sum<Lambda.IThing>(System.Collections.Generic.IEnumerable<Lambda.IThing>, System.Func<Lambda.IThing,decimal>)' and 'System.Linq.Enumerable.Sum<Lambda.IThing>(System.Collections.Generic.IEnumerable<Lambda.IThing>, System.Func<Lambda.IThing,decimal?>)'

: Sağ hata döndürür

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:Program.exe Program.cs

Ve şimdi derlemek decimal türünde doğru hata var. Öyleyse, precompiler kaynaklarda bir yere yerleştirdiğimiz garip bir derleyici hatası.

+1

Hmm, 'return things.Sum kullanıldığında (yeni Func (GetAmount));' Herhangi bir derleyici hatası almıyorum. Burada neler oluyor? VS2015 kullanıyorum. –

+0

@IvanStoev bu derleyici hatasını OP kodu ile aldım - "public decimal Total" (IThing [] şeyler) {return things.Sum (GetAmount); } ' –

+0

Görüyorum. Hala garip çünkü ben OP ile aynı hatayı alıyorum :) –

1

CS0121 ile ilişkili hata iletisi yalnızca ilk iki belirsiz eşleşmeyi gösterir. Hata, Sum'un tüm imzaları için geçerlidir.Sen Sum imza ile eşleşen bir uzantısı sınıfını yazma ve sınıf içindeki yöntemlerin sırasını değiştirerek bu kendini ispat: bir yöntemin dönüş türü bu imzasının bir parçası olarak kabul edilmez

public static class Extensions 
{ 
    public static decimal TestSum<T>(this IEnumerable<T> source, Func<T, decimal> selector) 
    { 
     return 0; 
    } 

    public static int TestSum<T>(this IEnumerable<T> source, Func<T, int> selector) 
    { 
     return 0; 
    } 

    public static int? TestSum<T>(this IEnumerable<T> source, Func<T, int?> selector) 
    { 
     return 0; 
    } 
} 

CS0121 The call is ambiguous between the following methods or properties: 
'Extensions.TestSum<T>(IEnumerable<T>, Func<T, decimal>)' and 
'Extensions.TestSum<T>(IEnumerable<T>, Func<T, int>)' 

. Yine sadece dönüş türleri farklı aynı ada sahip iki yöntem yazarak bu kanıtlayabilirim: Doğru imzasıyla bir Func kabul Sum bir aşırı ararken Yani

public class TestClass 
{ 
    public decimal TestReturn(int value) { return 0m; } 
    public int TestReturn(int value) { return 0; } 
} 

CS0111 Type 'TestClass' already defines a member called 'TestReturn' with the same parameter types 

, sadece parametreleri, görmediği Bu durumda, IThing türünde geri dönüş tipleri, Sum tüm aşırı yüklenmelerine uymasına neden olur ve bu nedenle belirsizdir.