Otrzymuję powyższy błąd i nie mogę go rozwiązać. Trochę googlowałem, ale nie mogę się tego pozbyć.
Scenariusz:
Mam klasę BudgetAllocate, której właściwością jest budżet typu double.
W moich dataAccessLayer,
Na jednym z moich zajęć staram się to zrobić:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Który generuje ten błąd:
Właściwość lub indeksator nie mogą być przekazywane jako parametr out lub ref w czasie kompilacji.
Próbowałem nawet tego:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Wszystko inne działa dobrze i istnieją odniesienia między warstwami.
c#
.net
error-handling
Pratik
źródło
źródło
DataGrid
wypełnić, nauczyłem się tego tylko automatycznie z właściwościami. Przełączenie na właściwości zepsuło niektóre parametry ref, których używałem na moich polach. Musisz zdefiniować zmienne lokalne, z którymi chcesz przeprowadzić analizę.Odpowiedzi:
nie możesz użyć
double.TryParse(objReader[i].ToString(), out bd.Budget);
zamień bd.Budget na jakąś zmienną.
double k; double.TryParse(objReader[i].ToString(), out k);
źródło
Inni podali ci rozwiązanie, ale dlaczego jest to konieczne: właściwość jest po prostu cukrem syntaktycznym dla metody .
Na przykład, gdy deklarujesz właściwość wywoływaną
Name
za pomocą metody pobierającej i ustawiającej, kompilator w rzeczywistości generuje metody o nazwieget_Name()
iset_Name(value)
. Następnie podczas odczytywania i zapisywania w tej właściwości kompilator tłumaczy te operacje na wywołania tych wygenerowanych metod.Jeśli wziąć pod uwagę to, staje się oczywiste, dlaczego nie można przekazać obiekt jako parametr wyjściowy - czy faktycznie przekazując odwołanie do metody , zamiast odniesienia do
obiektuzmiennej , która jest, co wyjście parametrów oczekuje.Podobny przypadek istnieje w przypadku indeksatorów.
źródło
To jest przypadek nieszczelnej abstrakcji. Właściwość jest w rzeczywistości metodą, metody dostępu get i set dla indeksatora są kompilowane do metod get_Index () i set_Index. Kompilator wykonuje świetną robotę ukrywając ten fakt, automatycznie tłumaczy przypisanie do właściwości na przykład na odpowiednią metodę set_Xxx ().
Ale to idzie do góry nogami, gdy przekażesz parametr metody przez odniesienie. Wymaga to od kompilatora JIT przekazania wskaźnika do lokalizacji pamięci przekazanego argumentu. Problem w tym, że takiego nie ma, przypisanie wartości właściwości wymaga wywołania metody ustawiającej. Wywołana metoda nie może odróżnić przekazanej zmiennej od przekazanej właściwości i dlatego nie może wiedzieć, czy wywołanie metody jest wymagane.
Godne uwagi jest to, że to faktycznie działa w VB.NET. Na przykład:
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
Kompilator VB.NET rozwiązuje ten problem, automatycznie generując ten kod dla metody Run, wyrażony w języku C #:
int temp = Prop; Test(ref temp); Prop = temp;
Które obejście można również zastosować. Nie do końca wiem, dlaczego zespół C # nie zastosował tego samego podejścia. Prawdopodobnie dlatego, że nie chcieli ukrywać potencjalnie kosztownych wywołań getter i setter. Lub całkowicie niezdiagnozowalne zachowanie, które otrzymasz, gdy ustawiacz ma efekty uboczne, które zmieniają wartość właściwości, znikną po przypisaniu. Klasyczna różnica między C # a VB.NET, C # to „bez niespodzianek”, a VB.NET to „zrób to, jeśli możesz”.
źródło
Umieść parametr out w zmiennej lokalnej, a następnie ustaw zmienną na
bd.Budget
:double tempVar = 0.0; if (double.TryParse(objReader[i].ToString(), out tempVar)) { bd.Budget = tempVar; }
Aktualizacja : bezpośrednio z MSDN:
źródło
Ewentualnie interesujące - możesz napisać własne:
//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; }
źródło
To jest bardzo stary post, ale poprawiam zaakceptowany, ponieważ istnieje jeszcze wygodniejszy sposób na zrobienie tego, którego nie znałem.
Nazywa się to deklaracją inline i mogło być zawsze dostępne (jak w przypadku używania instrukcji) lub mogło zostać dodane z C # 6.0 lub C # 7.0 w takich przypadkach, nie jestem pewien, ale i tak działa jak urok:
Poza tym
double temp; double.TryParse(objReader[i].ToString(), out temp); bd.Budget = temp;
Użyj tego:
double.TryParse(objReader[i].ToString(), out double temp); bd.Budget = temp;
źródło
Więc budżet to własność, prawda?
Zamiast tego najpierw ustaw ją na zmienną lokalną, a następnie ustaw na nią wartość właściwości.
double t = 0; double.TryParse(objReader[i].ToString(), out t); bd.Budget = t;
źródło
Zwykle, gdy próbuję to zrobić, dzieje się tak, ponieważ chcę ustawić swoją właściwość lub pozostawić ją jako wartość domyślną. Z pomocą tej odpowiedzi i
dynamic
typów możemy łatwo stworzyć metodę przedłużania ciągów, aby była jednolita i prosta.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); }
Użyj w ten sposób;
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
Opcjonalny
Na marginesie, jeśli tak jest
SQLDataReader
, możesz również użyćGetSafeString
rozszerzenia (rozszerzeń), aby uniknąć zerowych wyjątków od czytnika.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; }
Użyj w ten sposób;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double)); bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
źródło