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());
        }
    }

Я извиняюсь, если это не то, что вы хотите... но это все, что я могу придумать, и если кто-то думает, что это неправильный способ сделать это, пожалуйста, скажите почему!