עדי הראה לי רעיון מאוד מעניין למימוש שמירת אובייקט זמני בזיכרון. למה הכוונה ?
נניח שיש לנו קוד כזה
public class FileLogger : ILogger
{
}
public class MockLogger : ILogger
{
}
public class Person
{
public ILogger Logger { get; set; }
}
ויש לנו את פונקצייה שמקבלת כפרמטר Person אבל בחלק מהקוד של הפונקצייה לא רוצים שה - Logger יהיה FileLogger אלא MokeLogger - מן הסתם נעשה קוד כזה
public void Func(Person person)
{
ILogger original = person.Logger;
person.Logger = new MockLogger();
//work.....
person.Logger = original;
}
מה שעדי הציע - זה לעשות את הקוד הבא
using (DisposableProperty<ILogger>.Set(person, new MockLogger()))
{
// work..
}
וכעת באורח פלא בתוך בלוג ה - using ה - Logger יהיה Mock וכשנצא מהבלוק זה יחזור להיות ה - Logger המקורי.
הרעיון הזה הוא נהדר בסביבות Test - תחשבו על מקרים שאתם לא באמת מעוניינים לגשת לבסיס הנתונים למשל וכו', נכון שתמיד אפשר לכתוב כמו בדוגמא הראשונה אבל הקוד הרבה יותר אלגנטי בצורה הזאת.
אז איך זה עובד ?
public class DisposableProperty<T> : IDisposable where T : class
{
private T _original;
private PropertyInfo _property;
private object _obj;
private DisposableProperty(object obj, T replaceValue)
{
if (obj == null)
throw new ArgumentNullException();
this._obj = obj;
_property = obj.GetType().GetProperties().
FirstOrDefault(p => p.PropertyType == typeof(T));
if (_property == null)
throw new ArgumentException();
_original = _property.GetValue(obj, null) as T;
_property.SetValue(obj, replaceValue, null);
}
public void Dispose()
{
_property.SetValue(_obj, _original, null);
}
public static IDisposable Set(object obj, T replaceValue)
{
return new DisposableProperty<T>(obj, replaceValue);
}
}
אמנם לא הכי יעיל מבחינת ביצועים - אבל בדרך כלל קוד כזה ירוץ בסביבות Tests אז לא כל כך נורא.
המתודה Set מחזירה מופע חדש של המחלקה, בבנאי שומרים את המקורי וב - Dispose מחזירים את המקורי.