Laden...

Ein Bug bei LightCore (2)? (ReflectionActivator)

Erstellt von mouk vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.284 Views
M
mouk Themenstarter:in
9 Beiträge seit 2010
vor 13 Jahren
Ein Bug bei LightCore (2)? (ReflectionActivator)

Hallo,

hier ist ein weiter Bug-Report bzgl. LightCore.

Da mein letzter Beitrag nicht beantwortet wurde, bin ich mir nicht mehr sicher, ob das Forum der richtige Ort für Bugreports. Gibt mir bitte Bescheid, falls ich die Beiträge hätte woanders posten sollen.

Dieser Bug bezieht sich auf die Auswahl der Konstruktor. Sei eine Klasse mit zwei ctors: einem mit String Parameter und einem Ohne. Wird der Container einmal mit einem Wert aufgerufen, dann rufen folgende Resolve<>() -Aufrufe den ctor mit dem gleichen Parameter auf (auch wenn kein Parameter beim Resolve<>() angegeben wird). Der Test dafür steht unten. Der Bug liegt wahrscheinlich daran, dass _cachedConstructor in ReflectionActivator „zu viel“ cachet.

Viele Grüße,

Mouk




[TestMethod()]
        public void CachedConstructor()
        {
            var builder = new ContainerBuilder();
            builder.Register<TextHolder, TextHolder>().ControlledBy<TransientLifecycle>();
            var container = builder.Build();

            const string text = "TEXT";


            var firstInstance = container.Resolve<TextHolder>();
            container.Resolve<TextHolder>(text);

            var secondInstance  = container.Resolve<TextHolder>();
            
            Assert.AreEqual(firstInstance.Text,secondInstance.Text);
        }

        public class TextHolder
        {
            public string Text { get; set; }
            public TextHolder()
            {
                Console.WriteLine("Without text");
            }
            public TextHolder(string text)
            {
                Console.WriteLine("With");
                Text = text;
            }
        }
1.044 Beiträge seit 2008
vor 13 Jahren

Hallo mouk,

_TransientLifecycle _liefert immer eine neue Instanz. Weil immer eine neue Instanz geliefert wird, hat man somit zwei unterschiedliche Instanzen. Das Gegenstück wäre das SingletonLifecycle, was dir immer eine Instanz liefert, also ein Singleton.

Die Zeile container.Resolve<TextHolder>(text); macht in meinen Augen wenig Sinn. Die Methode dient dazu, etwas zurückzugeben, nicht etwas zu übergeben. Besser ist es, wenn du das direkt beim Builder mit builder.Register<TextHolder, TextHolder>().ControlledBy<TransientLifecycle>().WithArguments("zero_x"); übergibst.

Letzenendes hast du natürlich zwei Unterschiedliche Instanzen und somit auch zwei Werte. container.Resolve<TextHolder>(text); hat nicht so was wie eine "Rückbeziehung".

Verwende lieber container.Resolve<FooWithArguments> oder gibt das direkt beim Builder an.

Siehe auch Bug in LightCore? (ThreadSingletonLifecycle).

zero_x

M
mouk Themenstarter:in
9 Beiträge seit 2010
vor 13 Jahren

Hallo Zero_x,

danke für deine Antwort. Im Text habe ich in der Tat einen Fehler gemacht: nämlich

Assert.AreSame(firstInstance.Text,secondInstance.Text);

statt

Assert.AreEqual(firstInstance.Text,secondInstance.Text);

(Ich werde den Test modifizieren)

Ich vergleiche jedoch die Textwerte und nicht die Objekte. Es ist mir klar, dass transiente Objekte.. halt transient sind. Aber geht es darum, dass der gleiche Aufruf, nämlich

container.Resolve<TextHolder>();

zweimal 2 verschiedene ctors verwendet: einmal mit dem Text-Parameter und einmal ohne.

Die Zeile

Assert.AreEqual(firstInstance.Text,secondInstance.Text);

vergleich einfach die TextHolder.Text –Eingenschaften, um festzustellen, welcher ctor verwendet wurde.

Allgemein zu der Verwendung von

container.Resolve<TextHolder>(text); 

sehe ich kein Problem. Im Gegensatz zu der Angabe der Argumente beim Builder, sollte der Wert von „text“ bei einem Aufruf verwendet werden. Mit anderen Worten: ich will in einem Fall „text“ verwenden, und ansonstens immer die beim Builder eingestellten Konfigs.

Ich hoffe, ich konnte ein Bisschen erläutern, wo der Bug, meiner Meinung nach, liegt.

Der hinweis zu meinem anderen Beitrag habe ich nicht verstanden. Was hat das damit zu tun?

Gruß,

Mouk

1.044 Beiträge seit 2008
vor 13 Jahren

Hallo mouk,

du hast dich jetzt jedenfalls wiederholt. Alles, was ich sagte, hast du auch gesagt, nur in anderen Worten. Und was an container.Resolve<TextHolder>(text); nicht gut ist, sagte ich bereits(letzer Beitrag, zweiter Absatz). Ich kann immer noch nicht nachvollziehen, wo der Fehler in deinen Augen ist.

zero_x

P
20 Beiträge seit 2007
vor 13 Jahren

Moin, moin,

wenn ich Mouk richtig verstanden habe, geht es darum, dass zwar immer neue Instanzen erzeugt werden (also soweit richtig 😃 ), aber eben immer mit dem ZUERST benutzten Konstruktor, egal, ob es auch andere gibt, die man ggf durch den Container auflösen will. D. h. der zweite Resolve ruft den ctor aus dem Cache auf ohne zu prüfen, ob der die gleichen Argumente hat.
Aus meiner Sicht würde ich das ebenfalls als Bug bewerten.

cu
PolarKreis

Wer zu gross ist für die kleinen Dinge des Lebens,
ist meistens auch zu klein für die grossen

5.942 Beiträge seit 2005
vor 13 Jahren

Hallo mouk

Da mein letzter Beitrag nicht beantwortet wurde, bin ich mir nicht mehr sicher, ob das Forum der richtige Ort für Bugreports. Gibt mir bitte Bescheid, falls ich die Beiträge hätte woanders posten sollen.

Vielen Dank für deine Bugreports!
Der Ort passt soweit, ich bin bisher nur noch nicht dazu gekommen mich darum zu kümmern.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

M
mouk Themenstarter:in
9 Beiträge seit 2010
vor 13 Jahren

Hallo zusammen,

was PolarKreis sagt, ist richtig. Das Problem liegt beim verwendeten Konstruktor und nicht bei den transienten Instanzen.

Folgendes ist ein Auszug aus dem Quellcode von Container.cs:


         ///<summary>
        /// Resolves a contract (include subcontracts) with constructor arguments.
        ///</summary>
        ///<param name="arguments">The constructor arguments.</param>
        ///<typeparam name="TContract">The type of the contract.</typeparam>
        ///<returns>The resolved instance as <typeparamref name="TContract"/></returns>.
        public TContract Resolve<TContract>(params object[] arguments)
        {
            return this.Resolve<TContract>(arguments.ToList());
        }

Die Verwendung von der Methode Resolve(Konstruktorparameter) ist also legitim und von LightCore vorgesehen.

Der Aufruf


builder.Register<TextHolder, TextHolder>().ControlledBy<TransientLifecycle>().WithArguments("zero_x"); 

ist nicht besser, sondern ganz was anderes. Hier wird der Container so konfiguriert, dass er IMMER "zero_x" an den Konstruktor übergibt.

Hallo Peter,

wollte mich nur versichern, dass ich hier keine Monologe führe 😉

Viel Grüße,

Mouk