CS1501: Нет перегрузки для метода 'ToString' принимает 0 аргументов?
Как можно без перегрузки ToString принимать нулевые аргументы? Нулевой аргумент ToString является частью System.Object!
Изменить в ответ на закрытое голосование: Так как я не могу обновить свой сервер сборки до .NET 4.5, есть ли способ сделать этот код работать с компиляторами .NET 4.0/VS 2010? Короче говоря, моя перегрузка имеет совершенно другое имя, что просто не круто.
- Объект, о котором идет речь, является F # Discriminated Union, который переопределяет метод ToString, унаследованный от System.Object.
- Переопределенная ToString вызывается кодом в проекте С#, который является частью того же решения.
- Все это работало нормально, пока я не добавил дополнительную перегрузку ToString в мой дискриминационный союз, который принимает один аргумент.
- Все это прекрасно работает на моем локальном компьютере (VS 2012, все проекты, ориентированные на .NET 4.0).
- Он не работает на сервере сборки (.NET 4.0) - ошибка компилятора С# в заголовке появилась, как только я добавил 1-аргумент перегрузки ToString в мой дискриминационный союз.
Я думаю, что самым простым обходным решением было бы переименовать мою перегрузку ToString на что-то другое, но это причудливо.
Здесь простое воспроизведение. Вы можете скачать zip файл решения, содержащего этот код здесь: http://dl.dropbox.com/u/1742470/CS1501_Repro.zip
Компиляция этого решения в VS 2010 завершится с ошибкой "CS1501: перегрузка для метода" ToString "принимает 0 аргументов". Компиляция в VS 2012 будет работать просто отлично. В обоих случаях мы ориентируемся на .NET Framework 4.
F #
namespace CS1501_Repro.FSharp
open System
[<Serializable>]
type MyDiscriminatedUnion =
| Foo of int list
| Bar of string
| Baz of int
| Fizz of float
| Buzz of DateTimeOffset
override this.ToString() =
"Zero Arguments"
member this.ToString(lookup:Func<int,string>) =
"One Argument"
С#
using System;
using CS1501_Repro.FSharp;
namespace CS1501_Repro.CSharp
{
public class Caller
{
private MyDiscriminatedUnion _item;
public Caller(MyDiscriminatedUnion item)
{
_item = item;
}
public string DoThing()
{
return _item.ToString();
}
public string DoOtherThing()
{
return _item.ToString(i => i.ToString());
}
}
}
Ответы
Ответ 1
Это лишь частичный ответ, но я заметил, что VS2010 и VS2012 генерируют разные IL для класса F #. Если вы посмотрите на IL для метода ToString(lookup:Func<int,string>)
, вы увидите, что вывод в VS2010:
.method public instance string ToString(class [mscorlib]System.Func`2<int32,string> lookup) cil managed
{
// Code size 7 (0x7)
.maxstack 3
IL_0000: nop
IL_0001: ldstr "One Argument"
IL_0006: ret
} // end of method MyDiscriminatedUnion::ToString
а вывод в VS2012:
.method public hidebysig instance string
ToString(class [mscorlib]System.Func`2<int32,string> lookup) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "One Argument"
IL_0006: ret
} // end of method MyDiscriminatedUnion::ToString
Разница заключается в аннотации hidebysig
в сигнатуре метода. Если добавлен hidebysig
, тогда этот метод скроет другие реализации (в базовом классе), которые имеют одно и то же имя и подпись, а если hidebysig
опущен, он скроет все другие реализации с тем же именем, даже если подпись отличается. Этот вопрос о переполнении стека содержит хороший ответ, описывающий hidebysig
.
Итак, хотя этот ответ не решает вашу проблему, он объясняет, почему он не компилируется в VS2010.
Ответ 2
Я должен признать, что я впервые использовал F #, поэтому это решение, вероятно, не самое элегантное, однако вы упомянули, что ToString() является частью System.Object...
Я решил эту проблему, добавив строку кода в метод DoThing(), который присваивает _item объекту, а затем вызывает ToString() из объекта, давая в этом случае желаемый результат:
Код F # (без изменений)
type MyDiscriminatedUnion =
| Foo of int list
| Bar of string
| Baz of int
| Fizz of float
| Buzz of DateTimeOffset
override this.ToString() = "Zero Arguments"
member this.ToString(lookup:Func<int,string>) = "One Argument"
Код С# (см. изменение метода DoThing())
public class Caller
{
private Module1.MyDiscriminatedUnion _item;
public Caller(Module1.MyDiscriminatedUnion item)
{
_item = item;
}
public string DoThing()
{
object result = _item; //assign to object
return result.ToString(); //call ToString() on object
}
public string DoOtherThing()
{
return _item.ToString(i => i.ToString());
}
}
Я извиняюсь, если это не то, что вы хотите... но это все, что я могу придумать, и если кто-то думает, что это неправильный способ сделать это, пожалуйста, скажите почему!