2015-07-31 27 views
71

Mam metodę z następujących przeciążeń:Dlaczego ta obsada jest niepotrzebna?

string Call(string function, Dictionary<string, object> parameters, object body) 
string Call(string function, Dictionary<string, object> parameters, JObject body) 

Teraz dodaje inny przeciążenie:

string Call(string function) 
{ 
    return Call(function, null, (JObject) null); 
} 

dodałem obsady do JObject więc kompilator wie, jakie przeciążenie powinien go używać. Ale Visual Studio mówi mi, że obsada jest zbędna. Ale dlaczego moje wezwanie nie jest dwuznaczne?

+18

Nawet jeśli nie jest niejednoznaczny dla kompilatora, zatrzymam go tam, ponieważ może być niejednoznaczny dla osoby czytającej kod – Alex

+5

@jean Nie, to nie jest powód. Mówię kompilatorowi, którego przeciążenia użyć. I nie ma znaczenia, które przeciążenie metody jest stosowane, ponieważ mogą one mieć zupełnie inne implementacje. 'null' ma wartość' null', ale rzutowanie jest wskazówką, które przeciążenie powinno zostać użyte. – fero

+1

@jean Obawiam się, że znowu jest źle. Obsada jest tylko nadmiarowa, ponieważ kompilator będzie _still_ używał przeciążenia 'JObject', nawet jeśli nie będę rzutował na' JObject', ponieważ używa najbardziej specyficznego przeciążenia, które pasuje do parametrów, a 'null' może pasować do wszystkiego i' JObject' _jest_ bardziej specyficzne niż "obiekt". Zobacz odpowiedź Jona Skeeta, aby uzyskać szczegółowe wyjaśnienie. – fero

Odpowiedz

96

Ale dlaczego moje wezwanie nie jest niejednoznaczne bez obsady?

Ponieważ przeciążenie z parametrem JObject jest „lepszy” niż przeciążenia z parametrem object ... bo konwersja z null do JObject jest „lepszy” niż konwersja z null do object.

JObject jest bardziej szczegółowy niż object, ponieważ istnieje niejawna konwersja z JObject do object, ale nie odwrotnie.

Jeśli parametr końcowy dla pierwszej metody były string zamiast (na przykład) wtedy ani przeciążenie będzie lepiej niż inne, a połączenie byłoby być niejednoznaczne bez obsady.

Zobacz rozdział 7.5.3 specyfikacji C# 5 dla wszystkich zawiłych detali. W szczególności ma tu zastosowanie sekcja 7.5.3.5 ("lepszy cel konwersji").

+8

Nawet jeśli rzut nie jest potrzebny z klasą, jaka istnieje dzisiaj, niepowodzenie rzucania 'null' sprawi, że kod wywołujący będzie bardzo kruchy, ponieważ dodanie * prawie dowolnego * dodatkowego przeciążenia typu referencyjnego złamie kod wywołujący, który nie rzuca. Nie uważam, by jakikolwiek numer referencyjny o wartości zerowej był "zbędny" w przypadkach, w których istnieje realistyczna możliwość dodatkowego przeciążenia typu referencyjnego, które mogą stać się niejednoznaczne, lub nawet w tym przypadku w przypadkach, w których określone przeciążenie jest uważane za "lepsze" przez zasady, ale nie jest oczywiste, że jest to lepsze w sensie praktycznym. – supercat

+1

BTW, od dawna uważałem, że języki z przeciążeniem mogłyby w znacznym stopniu skorzystać z możliwości używania atrybutów lub innych sposobów określania pewnych przeciążeń powinny być uważane za "preferowane", jeśli są użyteczne, podczas gdy inne powinny być uważane za "awarie". "; Pomyślałem również, że byłoby pomocne, gdyby przeciążenie mogło określać typ parametru "null". Czy znasz jakieś języki, które robią takie rzeczy? – supercat

+0

@supercat: Nie, obawiam się, że nie. –