בעייה תכנונית ב DI.

Sea Bass

New member
בעייה תכנונית ב DI.

בכל הזמן שאני כותב תחת Dependency Injection משהו לא מסתדר לי ובכל פעם אני נתקל בזה מחדש.
נניח ש ILog או IMyDBContext מוזרק לי למחלקה בשם ClassA.
במחלקה כמובן אין לי שום דרך ליצור Instance חדש של ה Interfaces המוזרקים. רק להשתמש בהם.
אז מה הבעיה שלי?
בתוך ClassA יש לי מתודה (MyMethod) שצריכה לבצע New ל ClassB שה Ctor שלו מצפה של IMyContext. אז מה הבעיה אתם שואלים? פשוט נעשה (New ClassB(_mycontext ונשתמש. הענין הוא ש ClassB נניח עובד ב MultiThreading וכדי לעבוד נכון בכלל צריך להזריק לו Context חדש (נניח משתמשים ב EF) והמימוש ב ClassB הוא אסינכרוני.
אז איך אני מעביר לו Instance חדש של הסרוייס אם הוא מוזרק לי?
מקווה שהסברתי טוב.
תודה רבה.
 

Sea Bass

New member
Ninject אבל

מה זה משנה?
אגב ניתן לפתור את הבעיה על ידי שימוש ב ServiceLocator אבל אני מקבל את הרושם (ממה שאני קורא ולא משתכנע) שזה BadPattern.
 
Are you explicitly defining your bind()-ings

or trust NI to resolve it? Why not bind with proper scope?
ILog would be bound InSingletonScope()
IDbContext possibly InThreadScope()
 

Miki Watts

New member
אם אני זוכר נכון, בדרך כלל בספריות מהסוג הזה

אפשר להגדיר מחזור חיים של האובייקט שמוזרק, שזה יכול להיות סינגלטון, כלומר אתה תמיד תקבל את אותו אובייקט מחדש, או רגיל, שאז אתה מקבל instance חדש כל פעם. תנסה לראות אם יש אפשרות להגדיר את זה ב DI
 

Sea Bass

New member
אתה זוכר נכון אבל

זה עדיין לא פותר את הבעיה.
זה אומר שהאובייקט שיוזרק ל CTOR יהיה על פי מה שהוגדר.
אם אני רוצה לקחת אובייקט מה DI אז זה אומר שאני משתמש ב ServiceLocator כמו שמקודם רשמתי.
משהו בנוסח: ()<globalStaticService.Get<CContext t
 

nocgod

New member
אל תרד למצב של service-locator באמצעות DI

זה המצב הכי נורא שאתה יכול להגיע אליו
 
לכאורה יש כמה אפשרויות

1. להזריק גם את classB לתוך classA.
2. להזריק פקטורי. לדוגמא: IMyDbContextFactory.
3. או במקום להזריק מחלקת פקטורי, להזריק פונקציה.
public class ClassA(Func<ILogger> createLogger){
}
 

nocgod

New member
לכל בעיה - פיתרון =)

תעביר לו factory של הטיפוס אותו אתה לא יכול להזריק, או צריך לייצר בזמן ריצה, או instance שלו תלוי בפרמטר זמן ריצה.

public interface IDepedency() : IDisposable{
}public interface IDependencyFactory : IDisposable{ bool Disposed { get; private set; } IDepedency Create(/* parameters if needed*/); // kill a specific dependency bool Destroy(IDepedency dependency);}public class A : IDisposable{ IDependencyFactory _depFact; public A(IDependencyFactory depFact) { _depFact = depFact; } public void UseDependency(/* may contain some parameter needed for dependency creation */) { var dep = _depFact.Create(/*params*/); } public void Dispose() { if (!_depFact.Disposed) { _depFact.Dispose(); // should kill all created dependecies } }}
לא בדקתי שהקוד מתקמפל אבל זה הכיוון הכללי.
כל container שמכבד את עצמו (וגם ninject) מכיל קונספט שנקרא Typed-Factories. אתה יכול לראות דוגמא שכתבתי (תוך שימוש ב castle windsor) בשביל כל הכאב ראש הזה

a word of caution:
ה DbContext של EF לא בנוי לעבודה multi-threaded.

מקווה שזה עוזר לך, או שהבנתי את השאלה שלך נכון.
 

nocgod

New member
i didn't claim it was not covered

it is covered by lots of sources, that doesn't mean I can't add my example to show the idea.
 
That's good provided the example is correct.

The thing is your factory is expected to be instanciated by NI. Hence it should not be disposed by you. Hence 80% of your code should be deleted.

Seriously - RTFM
 

Sea Bass

New member
עדיין לא נתפס לי...

האם אני מזריק (וכותב) Factory לכל אובייקט? לא הגיוני..
ואם אני צריך להשתמש ב ClassC , ClassD, ClassE ...
ואם אני בכלל מזריק משהו שמייצר לי אובייקט אז למה לא להזריק IKarnel ואז לבצע <>Get ?
עוד שאלה.. איפה בכל הקוד הזה (גם חיפשתי בעוד מאמרים) אני מוצא את ה
(new classB(context ?
 

nocgod

New member
הרעיון הוא שאתה לא צריך לממש factory

אתה צריך ממשק ל factory ואז הקונטיינר עושה מימוש לבד, הוא גם מנהל את אורך החיים של האובייקטים אותם מייצר הfactory לפי ה policy שבאמצעותו רשמת את אותן תלויות.

אם אתה מזריק את ה kernel/container אתה לא עושה באמת DI אלא service-locator.

הרעיון הוא שתוכל לעשות classBFactory.Create(ctx) ולא לעשות new ClassVB(ctx) כאשר ה Factory של IClassB יהיה מוזרק ל ClassA
 

Sea Bass

New member
איך זה הגיוני

לייצר לכל אובייקט Factory משלו?
ClassBFactory
ClassVFactory
ClassZFactory
ואז אם אני רוצה לבצע שינוי באחד מה Ctor של האובייקטים (נניח ClassZ)
אז אני צריך ללכת ולהוסיף Create ב Factory?
מה אני מפספס פה?
 

nocgod

New member
אתה לא צריך לממש factory לכל אחד

בכל מקרה, אם תצרף קצת קוד דוגמא למה אתה מנסה להשיג יהיה הרבה יותר קל לענות לך...
 
למעלה