C# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס
-
שפה C#
יש לי קלאס שבודק מול ה'דאטה בייס' האם נתון קיים או לא
(SQL, שאילתא פשוטה שלif exists
שמחזירyes/no
)
שמיועד עבור 'אירועים' במערכת שמבצעים עדכון נתונים במסד הנתונים,
למניעת דריסת נתונים בשגגה ע"י המשתמש הנוכחי
(כגון: הנתון עודכן ע"י משתמש אחר במערכת)הפונקציה בקלאס מחזירה
string
שאותו אני בודק ב IF עצמולמניעת שגיאות זמן ריצה הפונקציה מכילה
try/catch
אני מעוניין
במידה ואכן היה תקלה בבדיקה (catch
)
לעצור את המשך הקוד דרך הפונקציה / הקלאסאבל פחות מעוניין לעשות זאת בכל עשרות המקומות בקוד
(if מקונן של שתי אפשריות )
מצורף דוגמת לינקפד
void Main() { TextBox tb = new TextBox(); tb.Dump(); Check_info ci = new Check_info(); tb.Click += (s, e) => { if (tb.Text.Length > 0) { if ("yes" == ci.CheckGiven_resul(tb.Text)) { "value found, no update made".Dump(); return; } "send update query".Dump(); } }; } class Check_info { public string CheckGiven_resul(string query) { string res; try { if (int.Parse(query) % 2 == 0) { res = "yes"; } else { res = "no"; } } catch { res = "error"; } return res; } }
התוצאה הרצויה בדוגמא
שאם הוזן טקסט (ולא מספר)
לא יודפס לי "send update query"
אלא יבוצע משהו מקביל לreturn
-
@mekev בוא נעשה סדר. אני מנסה להבין מה בדיוק קורה כאן, נוסח השאלה שלך מעורר בי כמה תמיהות:
- אתה מעוניין שאם יש ערך כלשהו בשדה בדאטא - לא יבוצע עדכון? תקרא את הערך ותבדוק אם הוא מכיל משהו.
- אתה מעוניין למנוע מצב שבו שני משתמשים מנסים לכתוב בו זמנית לאותו שדה? זו בפירוש אחריות שמוטלת על ה-DB ולא צריכה להיות מנוהלת על ידי הקוד בתוכנה.
- אפשר להשתמש ב-TryParse שלא זורק חריגה במקרה של כישלון המרה.
- באופן כללי אתה צודק שאין לחזור על עצמך בקוד. אתה אמור להפוך את תהליך הבדיקה לפונקציה בפני עצמה, ולקרוא לה 10 פעמים, לא לחזור על הקוד 10 פעמים.
- באופן כללי, נסה להמנע מלהשתמש ב-Try/Catch ככל האפשר. ברוב המוחלט של המקרים, יש דרך למנוע את החריגות מעיקרא, על ידי תכנון יותר טוב.
-
@OdedDvir כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
אתה מעוניין שאם יש ערך כלשהו בשדה בדאטא - לא יבוצע עדכון? תקרא את הערך ותבדוק אם הוא מכיל משהו.
זה אכן מה שמתרחש בחלקו הראשון של הפונקציה (מחזיר yes/no)
@OdedDvir כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
אתה מעוניין למנוע מצב שבו שני משתמשים מנסים לכתוב בו זמנית לאותו שדה? זו בפירוש אחריות שמוטלת על ה-DB ולא צריכה להיות מנוהלת על ידי הקוד בתוכנה.
אין לי בעיה עם הכתיבה ל DB
אני רוצה לוודא שהמשתמש יודע שיש כבר נתון בDB (קופץ חלונית של המידע הקיים - האם לעדכן, כן/לא)
ושבמקרה של שגיאה, לא יתבצע דריסת מידע קיים ללא אישור המשתמש@OdedDvir כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
אפשר להשתמש ב-TryParse שלא זורק חריגה במקרה של כישלון המרה.
נכון, אבל אני צריך את המידע על הכשלון
- בכדי לתקן את הקוד
- אחרת הקוד ימשיך לביצוע הפעולה הבאה במקום לעצור
-
@mekev כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
במידה ואכן היה תקלה בבדיקה ( catch)
לעצור את המשך הקוד דרך הפונקציה / הקלאסאם אני מבין טוב,
אתה רוצה לגרום מתוך פונקציה לעצור קוד בפונקציה הקוראת.
זה מעשה חריג מאוד, שלא מתאפשר בדרך רגילה למעט זריקת שגיאה.throw new Exception("error");
בתוך פונקציה יגרום לקוד הקורא להיצער, אבל גם הוא בתורו יגרום לקוד שקרא לו לעצור וכולי, עד שהתוכנה נסגרת בגלל זה (לשרשרת הזו קוראים call stack כלומר מחסנית קריאות). אם בקוד עליון יש טיפול בשגיאות, אז הקוד ייעצר שם.
כתבתי לך את זה לתיאוריה כי במעשי אם לא תכננת את זה אין מצב שזה יעבוד נכון.
אבל כפי שאמר @OdedDvir (שכל מילה שלו נכונה ומצויינת) עצם זה שיש לך הרבה מקומות לשנות הוא נושא שאתה צריך לנסות לרכז. צריך להיות מעט מאוד קוד שחוזר על עצמו, ואז הרבה יותר קל המקרים שנולדים כמו המקרה שאתה מציג.
כמובן תוכל להציג לנו דוגמת קוד שחוזר על עצמו, ונייעץ לך בס"ד איך אפשר לעשות אחד לכולם וככה האפליקציה שלך תיפטר מעשרות שורות. כל שורה = תחזוקה. -
@dovid כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
אם אני מבין טוב,
אתה רוצה לגרום מתוך פונקציה לעצור קוד בפונקציה הקוראת.אכן
הגדרה מדויקת של מה שאני מעוניין לבצע**
דוגמא:
חנות מחשבים המוכרת מחשבים בהרכבה אישית
טבלת ההזמנות נראית כך: (בפועל היא לא נראית כך, זה דוגמא בעלמא, נא לא להתמקד באיך אמורה להיות בנויה טבלה במסד נתונים )
ביצירת הזמנה נוצרת שורה חדשה הכוללת את שם המוצר / הלקוח (שאר הנתונים בעמודות כעת בערך null)
ולאחמ"כ במשך שבועיים
מתבצע לכל שורת הזמנה
הזמנות נפרדות של הרכיביםבאירוע של הלחצן להזמנת רכיב
אני מעוניין לפני שליחת ההזמנה
לבצע בדיקה האם הרכיב כבר הוזמןולכן אני מריץ בדיקה מול הDB האם תאריך הזמנת רכיב פלוני הינו null
במידה וזה אכן null
אני מעוניין לבצע הזמנהבמידה וקיים תאריך
אני מעוניין להציג את הנתון למשתמש
(בתאריך x הוזמן רכיב y מספק z, האם ברצונך לבצע הזמנה חוזרת?)היות ומדובר על עשרות לחצנים
כפי שהסביר ברהיטות ובטוב טעם @OdedDvir אין לבצע חזרה של כל הקוד בכל אירוע של לחצן, ויש למנוע הזנות משתמש שגויות, ולבצע בדיקת תקינות הקוד מראשאלא יש לי 'קלאס' כללי לכל הטפסים בתוכנה
שמכיל פונקציה המבצעת בדיקה מול הDB
שמחזירה סטרינג (yes/no)עד כאן הכל תקין וטוב לפי כל הכללים שציינתם
אז מה אני כן רוצה?
לי יש חשש שכן יתרחש חריג
כגון: במקרה שבו התרחש נפילת רשת רגעית בזמן ריצת השאילתא
והשאילתא מול הDB החזירה error (נזרק חריג, לא הצליחה לבצע חיבור לשרת)שזה מסוגי השגיאות שלא קשורות אלי (?)
או שיקרה מתישהו שפספסתי, ואכן אני הוא זה ששלח שאילתא שגויה לDBולכן שמתי בפונקציה try/catch
בכוונה גמורה ובדעה צלולה
ע"מ לקבל את החריגמה אני רוצה לעשות איתו?
ברמת המפתח: לנתח מדוע זה קרה, ולטפל
ברמת המשתמש:
אני מעוניין שיהיה שלושה מצבים
בקבלת ערך yes - המשך פעולה רציפה של הקוד
בקבלת ערך no - הצגת שאלה למשתמש שהערך קיים - ומה ברצונך לעשות
בקבלת ערך error - (א) להציג למשתמש שהתרחשה שגיאה, (ב) לחזור להתחלת הפונקציה, למצב של לפני לחיצה על הלחצן, (ג) להשאיר את התוכנה פתוחה ופעילה כפי שהיאיש לי את האפשרות הלא נכונה
שבכל אירוע אני יכניס את תוצאת הפונקציה למשתנה
ואז יבצע שתי בדיקות
אם הערך הוא no - תקפיץ את חלונית השאלה
ואם הערך הוא error תקפיץ את חלונית השגיאהלמה זה לא נכון?
בדיוק כפי שאמרתם
שהחלק של הטיפול בחריג - זה חוזר על עצמו, כפול, ומיותרלכן החלק של הטיפול בשגיאה
אני מעוניין לבצע מתוך הפונקציה - פעם אחת בלבד -
@mekev כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
למה זה לא נכון?
בדיוק כפי שאמרתם
שהחלק של הטיפול בחריג - זה חוזר על עצמו, כפול, ומיותראתה מדבר על יתירות הקוד של החלק של הטיפול בחריג,
ואנו התכוונו לקוד הקורא אל הפוקנציה שנמצא בהרבה מקומות.
צריך להיות קוד גנרי לכל המקרים הללו שקוראים לפונקציית הyes/no. -
@dovid כתב בC# איך לעצור המשך ריצת קוד, ב'catch' מפונקציה המחזירה string בקלאס:
צריך להיות קוד גנרי לכל המקרים הללו שקוראים לפונקציית הyes/no
כמדומני שאני משתמש בקוד בצורה די נכונה
ועדיין כמדומני שיש לי רצון לבצע את העצירה מהפונקציה
.
.אשתף מהקוד עצמו (בשינויים הכרחיים)
יש לי קלאס שמכיל כדלהלן:
class Class_query_for_CheckGiven_update_insert { SqlConnection con = new SqlConnection(Properties.Settings.Default.con); public string CheckGiven_resul(string query) { string query_if_exists = "if exists (" + query + " ) begin SELECT 'yes' as 'res' end else begin SELECT 'no' as 'res' end"; string res; try { if (con.State == ConnectionState.Open) { } else { con.Open(); } SqlCommand cmd = con.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandTimeout = 0; cmd.CommandText = query_if_exists; res = cmd.ExecuteScalar()?.ToString(); con.Close(); } catch (Exception ex) { res = "error"; if (con.State == ConnectionState.Open) { con.Close(); } else { } //טיפול בשגיאה בצורה שאינני מעוניין לפרט כרגע פה } return res; } }
.
.בתוכנה עצמה יש לי השמה כללית בצורה הזאת:
Class_query_for_CheckGiven_update_insert checkGiven_Update_Insert = new Class_query_for_CheckGiven_update_insert();
.
.
.ואז באירוע הלחצן אני מיישם כך:
//בדיקה האם הנתון קיים במסד if ("yes" == checkGiven_Update_Insert.CheckGiven_resul("select 1+1 = 5)) { //פתיחת טופס שאלה למשתמש עם אפשריות של כן - לא user_question_form_yes_no fyn = new User_question_form_yes_no("כאן אני מכניס טקסט משתנה לפי הצורך לתצוגת המשתמש"); fyn.ShowDialog(); if (fyn.Answer() == "no") { return; } } // המשך פעולת הקוד
-
@mekev
יש לנו סט פעולות שחוזרות על עצמם: בכל מקום מתבקשות הפעולות הבאות: 1. בדוק את המסד; 2. אם 1 =X הצג הודעה; 3. אם ההודעה נענתה בחיוב או ש1 = Y עשה Z.
הפונקציה CheckGiven_resul ממוקדת רק בלבדוק את מסד הנתונים, כלומר 1 מתוך שלוש. לפעמים קשה או נראה קשה לעשות פונקציה מפעולות דומות אך שונות. למשל אולי בכל מקום נוסח ההודעה שונה, כמובן שיכול להיות שהפעולה 3 שונה לחלוטין.
אבל באמת בעיצוב נכון אפשר הכל לרכז, וממילא הייתה מתייתרת לך השאלה.
אנחנו דוחים אותך "לך תעשה" בלי לעזור וזה אולי נראה בריחה מתשובה, אבל בכל מקרה לשאלה שלך באמת אין תשובה: אתה צריך לשכתב את כל המקומות. אם כבר תשתדל שזה יהיה הפעם האחרונה שזה הרבה מקומות (כמו תמיד אשמח לעזור לך גם בפרטי).