Почему для этого компилятору требуется запутанный синтаксис?

Или "я делаю это неправильно"?

Я пишу небольшую функцию, которая будет возвращать строку, заключенную в кавычки (как кавычки для печати), если это необходимо, в противном случае она возвращает ее как есть. В функцию вводится символ; результатом является строка.

То, что я пытался сделать сначала, было:

private string QuotedChar(char ch) {
    if(ch < (char)128 && !char.IsWhiteSpace(ch))
        return(new string(ch));

    // ...
}

Однако компилятор говорит CS0214: «Указатели и буферы фиксированного размера могут использоваться только в небезопасном контексте» при компиляции этого оператора возврата. Если я изменю код, чтобы сказать вместо этого:

private string QuotedChar(char ch) {
    if(ch < (char)128 && !char.IsWhiteSpace(ch))
        return(new string(new char[] { ch }));

    // ...
}

... он работает просто отлично. Однако это кажется довольно бессмысленным. Я не понимаю, почему он думает, что я пытаюсь использовать указатель или буфер фиксированного размера, поскольку это просто символ. Я пропустил что-то серьезно глупое, или это проблема/ошибка?

К вашему сведению, это Mono 2.0, а не Microsoft .NET Framework. Я не запускаю Windows, поэтому у меня нет компилятора Microsoft C#, чтобы увидеть, делает ли он то же самое или нет, поэтому мне интересно, является ли это ошибкой.


person Michael Trausch    schedule 01.04.2009    source источник


Ответы (5)


Ну, это не ошибка, что он не компилируется. Нет перегрузки строкового конструктора, который принимает char. Я подозреваю, что Моно подумал, что вы имели в виду конструктор string(char*), и попытался это сделать, что привело к ошибке.

Самый простой способ преобразовать char в string — просто вызвать ToString():

private string QuotedChar(char ch) {
    if(ch < (char)128 && !char.IsWhiteSpace(ch))
        return ch.ToString()

    // ... 
}

Компилятор MS C# угадывает ту же перегрузку, но выдает другое сообщение об ошибке:

Test.cs(8,20): ошибка CS1502: лучший перегруженный метод, соответствующий 'string.String(char*)', имеет несколько недопустимых аргументов
Test.cs(8,31): ошибка CS1503: аргумент '1': невозможно преобразовать 'char' в 'char*'

person Jon Skeet    schedule 01.04.2009
comment
Ага. Это работает. Интересно; Mono показал конструктор, который принимал char, хотя я не нашел его в MSDN. Я подозреваю, что вы можете быть правы в отношении указателя, поскольку он не показывает «char*» в таблице завершения в MonoDevelop. Спасибо! - person Michael Trausch; 01.04.2009
comment
Я подозреваю, что это ошибка MonoDevelop, которая просто неправильно показывает возможные перегрузки. - person Jon Skeet; 01.04.2009
comment
Казалось бы, так. Я отправлю отчет об ошибке, как только построю дерево из Subversion, чтобы подтвердить, что оно все еще там существует. - person Michael Trausch; 01.04.2009

Тот же код, скомпилированный в .NET, выдаст сообщение об ошибке, что не было перегрузки для строкового конструктора, который принимает char в качестве параметра. Ближайшее совпадение — это то, которое принимает указатель на char, поэтому, возможно, поэтому вы получаете это сообщение об ошибке в Mono.

Вы можете использовать перегрузку, которая принимает char и счетчик:

return new String(ch, 1);

Или вы можете использовать метод ToString:

return ch.ToString();

Или статический метод ToString:

return Char.ToString(ch);
person Guffa    schedule 01.04.2009

System.String не имеет конструктора, который принимает один символ.

Есть две возможности:

String(Char*)

or

String(Char[])

Вот почему ваш второй вариант работает, а первый думает, что вы пытаетесь передать указатель (небезопасно).

person Reed Copsey    schedule 01.04.2009

Для new string() нет перегрузки, которая занимает один символ. На самом деле вы получаете перегрузку, которая принимает char*, что означает, что она ожидает указатель на массив символов с завершающим нулем, но указатели разрешены только в небезопасном контексте.

Вместо создания массива вы можете сделать new string(ch, 1)

person Adam Robinson    schedule 01.04.2009

Я бы изменил вашу строку «вернуть новую строку (ch)» на строку «вернуть ch.ToString ()», не имеющую конструктора, который принимает один символ. Однако у него ДЕЙСТВИТЕЛЬНО есть тот, который принимает символ и счет.

вы можете использовать «новая строка (ch, 1)», чтобы создать строку, содержащую 1 символ, который будет тем, что находится в переменной ch.

person Muad'Dib    schedule 01.04.2009