Я получаю указанную выше ошибку и не могу ее исправить. Я немного погуглил, но не могу избавиться от этого.
Сценарий:
У меня есть класс BudgetAllocate, свойство которого - бюджет двойного типа.
В моем dataAccessLayer,
На одном из моих занятий я пытаюсь сделать это:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Что вызывает эту ошибку:
Свойство или индексатор нельзя передавать как параметр out или ref во время компиляции.
Я даже пробовал это:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Все остальное работает нормально и ссылки между слоями присутствуют.
c#
.net
error-handling
Pratik
источник
источник
DataGrid
будут заполнять, а затем я узнал, что он только автоматически со свойствами. При переключении на свойства были нарушены некоторые параметры ref, которые я использовал в своих полях. Для синтаксического анализа необходимо определить локальные переменные.Ответы:
ты не можешь использовать
double.TryParse(objReader[i].ToString(), out bd.Budget);
замените bd.Budget какой-нибудь переменной.
double k; double.TryParse(objReader[i].ToString(), out k);
источник
Другие дали вам решение, но почему это необходимо: свойство - это просто синтаксический сахар для метода .
Например, когда вы объявляете свойство, вызываемое
Name
с помощью методов получения и установки, под капотом компилятор фактически генерирует методы с именамиget_Name()
иset_Name(value)
. Затем, когда вы читаете и записываете в это свойство, компилятор переводит эти операции в вызовы этих сгенерированных методов.Если учесть это, становится понятно , почему вы не можете передать свойство в качестве выходного параметра - вы фактически передать ссылку на метод , а не ссылки на
объектпеременной , которая является какая ожидает параметр вывода.Аналогичный случай существует для индексаторов.
источник
Это случай дырявой абстракции. Свойство на самом деле является методом, методы доступа get и set для индексатора компилируются в методы get_Index () и set_Index. Компилятор делает потрясающую работу, скрывая этот факт, например, он автоматически переводит присвоение свойству соответствующего метода set_Xxx ().
Но это идет вверх, когда вы передаете параметр метода по ссылке. Это требует, чтобы JIT-компилятор передавал указатель на ячейку памяти переданного аргумента. Проблема в том, что его нет, присвоение значения свойства требует вызова метода установки. Вызываемый метод не может отличить переданную переменную от переданного свойства и, следовательно, не может знать, требуется ли вызов метода.
Примечательно то, что это действительно работает в VB.NET. Например:
Class Example Public Property Prop As Integer Public Sub Test(ByRef arg As Integer) arg = 42 End Sub Public Sub Run() Test(Prop) '' No problem End Sub End Class
Компилятор VB.NET решает эту проблему, автоматически генерируя этот код для метода Run, выраженный на C #:
int temp = Prop; Test(ref temp); Prop = temp;
Это обходной путь, который вы также можете использовать. Не совсем понимаю, почему команда C # не использовала тот же подход. Возможно, потому что они не хотели скрывать потенциально дорогие вызовы геттеров и сеттеров. Или совершенно недиагностируемое поведение, которое вы получите, когда у установщика есть побочные эффекты, которые изменяют значение свойства, они исчезнут после назначения. Классическая разница между C # и VB.NET, C # - «без сюрпризов», VB.NET - «заставить работать, если можно».
источник
Поместите параметр out в локальную переменную, а затем установите переменную в
bd.Budget
:double tempVar = 0.0; if (double.TryParse(objReader[i].ToString(), out tempVar)) { bd.Budget = tempVar; }
Обновление : прямо из MSDN:
источник
Возможно, интересно - вы можете написать свое:
//double.TryParse(, out bd.Budget); bool result = TryParse(s, value => bd.Budget = value); } public bool TryParse(string s, Action<double> setValue) { double value; var result = double.TryParse(s, out value); if (result) setValue(value); return result; }
источник
Это очень старый пост, но я исправляю принятый, потому что есть еще более удобный способ сделать это, о котором я не знал.
Это называется встроенным объявлением и может быть всегда доступно (как в операторах using) или может быть добавлено в C # 6.0 или C # 7.0 для таких случаев, не уверен, но в любом случае работает как шарм:
Inetad этого
double temp; double.TryParse(objReader[i].ToString(), out temp); bd.Budget = temp;
использовать это:
double.TryParse(objReader[i].ToString(), out double temp); bd.Budget = temp;
источник
Итак, бюджет - это собственность, верно?
Скорее сначала установите его в локальную переменную, а затем установите для нее значение свойства.
double t = 0; double.TryParse(objReader[i].ToString(), out t); bd.Budget = t;
источник
Обычно, когда я пытаюсь это сделать, я хочу установить свое свойство или оставить его по умолчанию. С помощью этого ответа и
dynamic
типов мы можем легко создать метод расширения строки, чтобы он оставался единым и простым.public static dynamic ParseAny(this string text, Type type) { var converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.IsValid(text)) return converter.ConvertFromString(text); else return Activator.CreateInstance(type); }
Используйте так;
bd.Budget = objReader[i].ToString().ParseAny(typeof(double)); // Examples int intTest = "1234".ParseAny(typeof(int)); // Result: 1234 double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34 decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34 decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0 string nullStr = null; decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0
По желанию
С другой стороны, если это так,
SQLDataReader
вы также можете использоватьGetSafeString
расширения, чтобы избежать нулевых исключений от читателя.public static string GetSafeString(this SqlDataReader reader, int colIndex) { if (!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); return string.Empty; } public static string GetSafeString(this SqlDataReader reader, string colName) { int colIndex = reader.GetOrdinal(colName); if (!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); return string.Empty; }
Используйте так;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double)); bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
источник