Laden...
D
Dust Signs myCSharp.de - Member
Programmierer Salzburg Dabei seit 04.06.2006 95 Beiträge
Benutzerbeschreibung

Forenbeiträge von Dust Signs Ingesamt 95 Beiträge

06.03.2014 - 12:39 Uhr

Das hilft mir nicht - ich suche nach einem Workaround, damit ich an diesem Projekt weiterarbeiten kann. Wenn's sein muss, kann ich auch die IDE wechseln, sofern mir dadurch keine Kompatibilitätsprobleme entstehen.

Dust Signs

05.03.2014 - 19:33 Uhr

Da der Designer in keiner seiner Funktionen mit Generics umgehen kann

Ist das offiziell und - falls ja - warum erzeugt die IDE ungültigen Code anstatt zu warnen oder einen aussagekräftigen Fehler anzuzeigen?

Beste Grüße
Dust Signs

04.03.2014 - 14:24 Uhr

Das mit object als Typparameter war nur eine Vereinfachung für mein obiges Minimalbeispiel. Im tatsächlichen Code geht es um einige dutzend Events mit weit komplexeren generischen Typparametern.

Beste Grüße
Dust Signs

04.03.2014 - 13:51 Uhr

Wenn ich das Event so deklariere

    public class TestClass<T>
    {
        
    }

    public class TestUserControl : UserControl
    {
        public TestClass<object> TestValue;

        public event EventHandler<TestClass<object>> TestEvent;

        public void FireTestEvent()
        {
            if (TestEvent != null)
                TestEvent(this, TestValue);
        }
    }

erscheint "TestEvent" nicht mehr im Eigenschaftsdialog.
Außerdem wäre das kein für mich praktisch relevanter Workaround, da ich am bestehenden Projekt aus Kompatibilitätsgründen kaum etwas am Klassendesign ändern kann.

Beste Grüße
Dust Signs

04.03.2014 - 10:25 Uhr

Hallo!

Ich versuche seit sehr langer Zeit die Ursachen für das Auftreten eines Visual-Studio-Bugs zu finden, der mich seit drei Versionen "begleitet" und mich in einem Altlasten-Projekt fast in den Wahnsinn treibt. Heute ist es mir endlich gelungen, das Auftreten des Bugs durch folgendes Minimalbeispiel zu provozieren:

    public class TestClass<T>
    {
        public delegate void TestDelegate(TestClass<T> test);
    }

    public class TestUserControl : UserControl
    {
        public TestClass<object> TestValue;

        public event TestClass<object>.TestDelegate TestEvent;

        public void FireTestEvent()
        {
            if (TestEvent != null)
                TestEvent(TestValue);
        }
    }

Fügt man ein solches TestUserControl im Visual-Studio-Designer in eine (Winforms-)Form ein und doppelklickt im Eigenschaftsfenster bei den Events das "TestEvent", passiert (nach Zufallsprinzip) entweder
* Gar nichts oder
* Eine Access Violation
Im zweiteren Fall muss ich die IDE aufgrund des laufenden Auftretens weiterer Fehlermeldungen über den Taskmanager schließen. Im ersteren Fall wird im Code folgende Zeile erzeugt:

        private void testUserControl1_TestEvent()
        {

        }

Im Designer-Code wird zusätzlich diese Zeile erzeugt:

this.testUserControl1.TestEvent += new WindowsFormsApplication1.TestClass<object>.TestDelegate(this.testUserControl1_TestEvent);

Das kompiliert natürlich nicht (die erzeugte Methode hat keine Parameter) und führt zu allerlei Folgefehlern. Zwar kann man die händisch korrigieren, aber das ist einerseits aufwändig und andererseits mit IDE-Restarts verbunden, wenn die IDE sich entscheidet, Access Violations zu werfen (siehe oben).
Durch Erstellen des Minimalbeispiels konnte ich die Ursache für den Fehler eingrenzen: Es liegt an dieser speziellen Form der generischen Parameter. Wandle ich den Delegatentyp minimal ab (z.B. so, dass der Parameter "test" vom Typ T ist), tritt der Fehler nicht auf.
Da ich ein Altlastenprojekt zu betreuen habe, das Dutzende Events dieser Art hat, kann ich den Designer nicht oder nur mehr sehr eingeschränkt verwenden, was das Arbeiten sehr umständlich und nervenaufreibend macht. Kann jemand das Problem reproduzieren und - noch wichtiger - gibt es irgendeinen Workaround? Das Problem tritt bei mir in VS Express 2013 auf, war aber wie gesagt auch schon in VS Express 2012 und 2010 vorhanden.

Danke im Voraus
Beste Grüße
Dust Signs

05.07.2013 - 08:56 Uhr

Diese Einschränkung bringt das Konzept der Kovarianz mit sich:

You can mark a generic type parameter as covariant if it is used only as a method return type and is not used as a type of formal method parameters.

FAQ zum Thema Ko- und Kontravarianz findest du z.B. hier Covariance and Contravariance FAQ und hier: Exact rules for variance validity.

Beste Grüße
Dust Signs

04.07.2013 - 18:38 Uhr

Hallo!

Vielleicht verstehe ich deine Frage falsch, aber wäre das nicht ein Anwendungsfall für Kovarianz?

    public interface IRepository<out T> //Man beachte das out!
    {
    };

    public class DummyRepository<T> : IRepository<T>
    {
    };

    public partial class MainWindow : Window
    {
        private IDictionary<Type, IRepository<object>> _repositories = new Dictionary<Type, IRepository<object>>();

        public MainWindow()
        {
            InitializeComponent();

            DummyRepository<object> r1 = new DummyRepository<object>();
            DummyRepository<string> r2 = new DummyRepository<string>();
            _repositories.Add(typeof(object), r1);
            _repositories.Add(typeof(string), r2);
        }
    }

Beste Grüße
Dust Signs

19.05.2013 - 14:22 Uhr

Hallo herbivore!

Danke für den Tipp. Wo würde man dieses Dictionary optimalerweise speichern? Global ist nicht wirklich schön, aber pro Wrapper macht es keinen Sinn.
//EDIT: Ich hab es jetzt so gelöst, dass jede Klasse eine Referenz auf das Dictionary hält und dieses von User bereitgestellt werden muss. Das funktioniert soweit. Danke nochmal.

Beste Grüße
Dust Signs

19.05.2013 - 10:21 Uhr

Hallo!

Ich habe in einem aktuellen Projekt eine Menge von Bauteilen, die ich durch entsprechende Klassen abbilde, die alle von einer Basisklasse Bauteil erben. Die Instanzen dieser Klassen sind miteinander assoziiert (meist in einer Art Eltern-Kind-Beziehung), um Schaltungen und Schaltungsgruppen nachzubilden.
Für die grafische Aufbereitung schreibe ich nun verschiedene Wrapperklassen (die von einer von Bauteil verschiedenen Basisklasse erben), die mit jeweils einem Bauteil verknüpft sind und diesem Position, Farbe und ähnliches zuordnen. Bei einzelnen Bauteilen, die nicht mit anderen verknüpft sind, funktioniert das einwandfrei.
Nun möchte ich aber die Assoziationen der abgebildeten Bauteile untereinander in irgendeiner Form in den Wrapper-Klassen-Instanzen abbilden, ohne diese händisch aneinander anpassen zu müssen. Vom Prinzip her suche ich nach einem Hilfskonstrukt, das es mir erlaubt, die Assoziationen der Bauteile und die Assoziationen ihrer dazugehörigen Wrapper abzubilden und kosistent zu halten.
Zur Illustration vielleicht noch ein kurzes Beispiel: Ich habe eine Bauteilgruppe BG mit zwei Bauteilen B1 und B2. B1 und B2 haben BG als "Parent", BG hat B1 und B2 jeweils als "Child". Nun habe ich für jedes dieser Bauteile einen Wrapper - WBG, WB1 und WB2 -, die mit den jeweiligen Bauteilen assoziiert sind. Wie kann ich die Assoziationen zwischen B1, B2 und BG auf WB1, WB2 und WBG abbilden (oder übertragen), ohne das händisch machen zu müssen und evtl. sogar auf Änderungen entsprechend reagieren, damit beides konsistent bleibt? Für Vorschläge wäre ich dankbar.

Frohen Pfingstsonntag
Beste Grüße
Dust Signs

15.05.2013 - 19:42 Uhr

Hallo!

Gibt es einen besonderen Grund, warum du eine List aus KeyValuePairs anstatt eines einfacheren SortedDictionary verwendest?

Beste Grüße
Dust Signs

18.09.2012 - 07:27 Uhr

Hallo herbivore!

Ich hab mich mal etwas in diese OR-Thematik eingelesen und sehe sehr viele Parallelen zu meinem aktuellen Problem. Ich denke, ich werde mir das noch etwas genauer ansehen und mir einige Ansätze aus dieser OR-Welt ausborgen. In jedem Fall bin ich zuversichtlich, damit mein Problem lösen zu können. Vielen Dank für den Hinweis.

Beste Grüße
Dust Signs

15.09.2012 - 09:20 Uhr

Hallo herbivore!

Sorry für die häppchenweise Information, aber ich hatte anfangs gedacht, dass die Menge an Erstinfos ausreicht, um die Frage zu beantworten (was offenbar nicht der Fall war). Ich wollte den sehr komplexen Sachverhalt etwas vereinfachen, damit ich nicht seitenweise jedes Detail beschreiben muss, was vielleicht gar wichtig ist. Ich bin sehr dankbar für die bisherigen Antworten, da sie einige Richtungen aufgezeigt haben, an die ich noch gar nicht gedacht hatte.
Zum Thema: Ja, es ist eine Art DataBinding zwischen Objekten, die momentan unschönerweise so gelöst wird, dass jedes Objekt eine Parser-Property hat, die jede auf denselben Parser verweist, der in der Lage ist, die Objektnamen beim Parsen aufzulösen und sich eine Art Call-Stack zu merken, damit bei Zirkelbezügen eine Exception geworfen werden kann. Die Kindklassen können den Parser mit ihrer Expression aufrufen, um den Wert der (berechneten) Property zu erhalten (z.B. um sich selbst zeichnen zu können) - so wie man auch von außen auf die Properties zugreifen kann.
Ich hoffe, ich habe keine weiteren Infos "vergessen", die eventuell relevant sein könnten. Falls doch, bitte ich um Nachsicht - das vorliegende Projekt ist äußerst komplex.

Dust Signs

14.09.2012 - 14:38 Uhr

Es ist eine Bibliothek und die Trennung liegt darin begründet, dass es Anwendungen gibt, die eine möglichst kleine Version der Library einbinden möchten, d.h. ohne Parser und sonstigen Schnickschnack. Mit Express-Versionen o.ä. hat das nichts zu tun.
Zur Verantwortung des Containers: Die Idee gefällt mir zwar prinzipiell gut, aber die Objekte müssen auch ohne einen Container auswertbar sein. Das macht jetzt im Minimalbeispiel mit einem Circle und einer Line nicht viel Sinn, ist bei komplexeren Objekten (die zu erklären den Rahmen hier sprengen würde und auch nicht passend wäre) allerdings durchaus sinnvoll.

Dust Signs

14.09.2012 - 13:51 Uhr

Ja, es geht um eine ähnliche Anwendung. INotifyPropertyChanged kann ich zwar verwenden, aber es löst mein Problem nicht, dass der Benutzer Ausdrücke in Form von Strings spezifizieren können soll, um die Objekte zu beschreiben, während die "Basiskonfiguration" diese Möglichkeit nicht bieten kann (dort gibt es nur die double-Properties).

Dust Signs

14.09.2012 - 09:08 Uhr

Hallo herbivore!

Es ist nicht schön, aber für komplexe Expressions durchaus geeignet. Wenn ich beispielsweise einen Circle habe, dessen Radius von der Steigung einer Gerade, d.h. von einem anderen Objekt, abhängt (Beispiel-Expression: "MeineGerade.Steigung" o.ä.), reicht es, auf die Radius-Property des Kreises zuzugreifen, ohne sich selbst um die weitere Abhängigkeit kümmern zu müssen.
Ich bin beim Klassendesign relativ offen für Vorschläge, benötige aber in jedem Fall die Möglichkeit, Circle-Klassen ohne Parser für die Basiskonfiguration anzubieten. Ob ich für die Klassen mit Parser eigene Unterklassen benötige, ist für mich nicht wichtig. Momentan habe ich diese Parseable*-Klassen, bin aber mit dem duplizierten Code unglücklich (alle Konstruktoren und Operatoren nebst XML-Dokumentation müssen händisch übernommen werden). Wenn es eine schönere Lösung gibt, immer her damit 😃.

Dust Signs

14.09.2012 - 07:45 Uhr

Hallo gfoidl!

Vielen Dank für deine umfangreiche Antwort. Es scheint allerdings, als hätte ich vorhin zu stark vereinfacht, denn was tatsächlich passiert ist, dass die jeweiligen Klassen sich selbst zeichnen und damit auch selbst Zugriff auf die aktuellen Werte der Properties haben müssen. Das heißt, dass jede Instanz unbedingt eine Parser-Property benötigt, deren Parse-Methode sie aufrufen kann.
Prinzipiell gefällt mir dein Ansatz aber recht gut, weil er jede Menge Code spart. Sehe ich richtig, dass ich das Interface "nur" um einen Parser erweitern müsste, damit jede Kindklasse auch eine Parser-Instanz hat, auf die sie selbst zugreifen kann?

Dust Signs

13.09.2012 - 20:02 Uhr

Beispiel zur Initialisierung der Circle-Klasse:

Circle MeinCircle = new Circle() { Radius = 3 };

Beispiel zur Initialisierung der ParseableCircle-Klasse:

ParseableCircle MeinCircle = new ParseableCircle() { RadiusExpression = "1 + 2" };

Beipiel zur Verwendung beider Klassen:

double r = MeinCircle.Radius;
Graphics.DrawEllipse(IrgendeinPen, 0, 0, 2 * r, 2 * r);

Das ist wie gesagt eine sehr starke Vereinfachung, sollte aber die Verwendung zeigen.

Dust Signs

13.09.2012 - 17:40 Uhr

Hallo gfoidl!

Stark vereinfacht:

class Circle
{
  public double Radius { get; set; }
}

class Line
{
  public double Slope { get; set; }
  public double Offset { get; set; }
}

Jetzt gibt es im Projekt einige Zusatzdateien, die je nach Projektkonfiguration und Präprozessor-Flags hinzugeschaltet werden können. Darunter befindet sich ein Parser:

class Parser
{
  double Parse(string Expression)
  {
    //...
  }
}

In dieser Konfiguration soll es jetzt zusätzlich zu Circle, Line etc. Klassen geben, die ein Setzen ihrer Eigenschaften als Ausdruck erlauben. Momentan ist das z.B. für Circle (unschön) so gelöst:

class ParseableCircle : Circle
{
  public Parser RadiusParser;
  public string RadiusExpression { get; set; }  
  public new double Radius { get { return RadiusParser.Parse(Expression); } set { Expression = value.ToString(); } }
}

Das ist jetzt alles sehr stark vereinfacht, sollte aber die aktuelle Klassenstruktur zeigen. Reicht das fürs Verständnis oder brauchst du mehr Details?

Dust Signs

13.09.2012 - 16:20 Uhr

Das mit "new" ist mir klar, aber das erspart mir trotzdem nicht, in jeder Kindklasse für jede Property den Parser und den String händisch zu definieren. Bzgl. des Parsens meinte ich nicht double.Parse, sondern das Parsen mittels einer eigenen Klasse.
Ich hatte zu Beginn Interfaces in Betracht gezogen, aber die scheiden aus, da diese nur eine einzige Expression erzwingen könnten und auch nicht erfordern, dass die Kindklasse die zu verdeckende Property überschreibt.

Dust Signs

13.09.2012 - 15:24 Uhr

Hallo!

Ich habe ein Projekt mit mehreren verschiedenen Klassen, die jeweils unterschiedliche Properties vom Typ double haben, z.B. einen Typ Kreis mit der Property Radius und einen Typ Gerade mit der Property Steigung. Nun sollen entweder Kindklassen abgeleitet oder die bestehenden Klassen erweitert werden, sodass die Properties über einen Ausdruck (vom Typ String) und einem Parser, der diesen Ausdruck verarbeiten kann, repräsentiert werden. Im obigen Beispiel hätte die Klasse Kreis dann beispielsweise eine Property RadiusExpression vom Typ String. Beim Lesen der (überschriebene) Radius-Property würde dann mittels des Parsers der Ausdruck auswertet und das Ergebnis zurückgeliefert.
Mir ist klar, dass das für jede einzelne Änderung theoretisch trivial lösbar ist, aber mein Projekt hat Dutzende Klassen mit jeweils mehreren Properties, weswegen ich nach einer Möglichkeit suche, das schöner zu lösen. Ich dachte an Attribute in den Elternklassen, aber das ermöglicht weiterhin das Lesen und Schreiben der Originalproperties. Aktuell habe ich für die wichtigsten Klassen Kindklassen implementiert, in denen ich die Expressions und die dazugehörigen Parser händisch als Properties hinzugefügt habe und entsprechend behandle, aber das ist sehr mühselig. Gibt es Alternativen, evtl. sogar ein passendes Designpattern?

Beste Grüße
Dust Signs

09.09.2012 - 16:32 Uhr

Hallo!

Ich versuche gerade, eine Lösung für folgendes Problem zu finden: Ich habe einen beliebigen nicht-primitiven Werttyp (also irgendeine Struktur), der eine Methode anbieten soll, die einige seiner Werte in einer bestimmten Art und Weise ändert. Das ginge zwar theoretisch mit einem Interface, scheitert aber praktisch daran, dass beim Aufruf von

(MeineVariable as IIrgendwas).Methode(EinParameter);

MeineVariable vom Werttyp "geboxed" wird und alle Änderungen, die der Aufruf der Methode verursacht hat, die "geboxede" Instanz ändern und nicht MeineVariable, d.h. die Änderungen im Prinzip verworfen werden.
Deklariere ich MeineVariable direkt als vom Werttyp, der das Interface implementiert, kann ich zwar über

MeineVariable.Methode(EinParameter);

das erreichen, was ich will, verliere aber die Fähigkeit, das für beliebige Werttypen zu machen. Da Strukturen nicht von anderen Strukturen erben können, kann ich das Vorhandensein der Methode aber nicht erzwingen.
Meine Frage: Gibt es dennoch irgendeine Möglichkeit, eine solche Methode in verschiedenen Werttypen einzufordern und diese anschließend so aufzurufen, dass die Daten der Werttypvariable geändert werden?

Grüße
Dust Signs

//EDIT: Ich habe gerade eine Lösung gefunden:

IIrgendwas temp = MeineVariable as IIrgendwas;
temp.Methode(EinParameter);
MeineVariable = (MeinTyp)temp;

Damit wird der Inhalt der Variable überschrieben und ich bekomme genau das Verhalten, das ich haben möchte. Mit MeinTyp als generischem Typparameter lässt sich das Ganze obendrein schön verallgemeinern

03.09.2012 - 20:55 Uhr

Danke für die rasche Antwort - das hatte ich mir fast gedacht.

Das wäre zwar für deinen Anwendungsfall besser, aber im allgemeinen betrachtet nicht unbedingt.

Warum? Es kann ohnehin keine Variante von Bazz aufgerufen werden, deren Typparameter die o.g. Einschränkungen hat, da der Compiler sonst meckern würde.

Grüße
Dust Signs

03.09.2012 - 20:22 Uhr

Hallo!

Ich bin gerade über ein Phänomen mit Generics gestolpert, dessen Ursache mir nicht ganz klar ist. Illustrieren lässt es sich an folgendem Minimalbeispiel:

        interface Dummy { }

        class Foo<T> where T : Dummy, new() { }

        class Bar
        {
            void Bazz<T>(Foo<T> foo_alt)
            {
                //...
                Foo<T> foo_neu = new Foo<T>();
                //...
            }
        }

Es kompiliert nicht, da der Compiler der Meinung ist, T wäre nicht vom Typ Dummy und hätte auch keinen parameterlosen Konstruktor. T muss aber vom Typ Dummy sein und einen parameterlosen Konstruktor haben, da der Typparameter des Parameters Foo verlangt, dass dem so ist.
Mir ist zwar klar, dass ich den Fehler korrigieren kann, indem ich hinter den Methodenkopf von Bar.Bazz

where T : Dummy, new()

schreibe, aber ich frage mich, warum das nicht auch so funktioniert. Löst der Compiler das nicht auf?
Ich frage, da ich in einem aktuellen Projekt einige hundert solcher Methoden mit generischen Typparametern habe, hinter die ich die jeweiligen Einschränkungen händisch schreiben muss - was nicht nur unschön, sondern auch zeitaufwändig ist. Ich hatte gehofft, hier evtl. eine schönere Lösung zu finden, so es denn eine gibt.

Grüße
Dust Signs

23.07.2012 - 14:49 Uhr

Nein, warum machst du das überhaupt.

Hauptsächlich benötige ich diese Information für einen eigenen Serializer, mit dem ich einige spezielle Anforderungen erfüllen muss, die mir weder die im Framework eingebauten noch die sonst verfügbaren Serializer erfüllen können.

  1. Warum ILMerge oder Netz?

Am Schluss muss eine Assembly herauskommen. Diese Einschränkung stammt nicht von mir, sondern ist von außen vorgegeben.

  1. Warum benutzt du überhaupt die Versionsnummer, wenn die ( deinen Angaben nach ) doch sowieso obsolet ist?

Auch das ist von außer vorgegeben.

Dust Signs

23.07.2012 - 13:43 Uhr

Die Versionsnummer kodiert in meinem Anwendungsfall das Builddatum und wird daher zur Speicherung dieser Information verwendet. Die Struktur der Typen ändert sich über die Versionen hinweg nicht, weswegen ich die Version nicht überprüfen muss.
Zudem verstehe ich nicht, was du mit

aber die ( z.b. von herbivore ignorierte ) willst du nicht hören meinst: Ich habe ILMerge durch .NETZ ersetzt und bin nun dadurch auf andere Workarounds angewiesen, die ich oben beschrieben habe.

Dust Signs

23.07.2012 - 11:40 Uhr

Das mag sein, aber momentan ist das die einzige Lösung, die zuverlässig funktioniert. Mir wäre es auch lieber, wenn ich die Assembly-Auflösung nicht händisch und unter Zuhilfenahme dieser Beobachtungen bzgl. der Reihenfolge machen müsste, aber anders funktioniert es leider nicht.
Falls jemand Alternativen kennt, bitte immer her damit 😃

Dust Signs

22.07.2012 - 22:02 Uhr

Hallo Roland!

Das Programm scheint soweit noch einwandfrei zu funktionieren. Soweit ich erkennen kann, ist momentan nur die "Haupt"-, d.h. Einsprungs-Assembly doppelt gelistet - einmal ohne Pfad mit dem den eigentlichen Klassen etc., und einmal mit Pfad und mit nur einer NETZ_0_4_8-Klasse (die wahrscheinlich für die Dekomprimierung und das Laden zuständig ist). Das scheint sonst nichts weiter zu beeinträchtigen.

Grüße
Dust Signs

20.07.2012 - 17:43 Uhr

Hallo!

Ich habe .NETZ ausprobiert - danke für euren Hinweis. Es löst das Problem prinzipiell, schafft aber auch ein neues - die Berücksichtigung unterschiedlicher Versionen über das AssemblyResolve-Event funktioniert nun nicht mehr. Nach einigen Stunden des Debuggens habe ich herausgefunden, dass das AssemblyResolve-Event in den .NETZ-Executables gar nicht mehr aufgerufen wird. Damit ist die "Lösung" für mich keine wirkliche, da ich das Problem mit den unterschiedlichen Assembly-Versionen, das ich schon gelöst hatte, nun nicht mehr lösen kann. Oder gibt es irgendeinen Workaround dazu?

EDIT: Ich habe die Lösung gefunden: Die .NETZ-Executable listet manche Assemblies in AppDomain.CurrentDomain.GetAssemblies() doppelt. Sucht man anhand des Assembly-Namen die Assembly manuell in der o.g. Liste, wählt den zweiten Treffer (nicht den ersten), kann man mittels GefundeneAssembly.GetType(...) den richtigen Typ bekommen.

Grüße
Dust Signs

18.07.2012 - 09:21 Uhr

Danke für den Hinweis mit .NETZ. Ich werde das mal an Stelle von ILMerge versuchen.

Grüße
Dust Signs

18.07.2012 - 07:46 Uhr

Hallo!

Vielleicht habe ich mich zu kompliziert ausgedrückt. Ich gebe mal ein konkretes Beispiel: Die mit ILMerge zu M zusammengefügten Assemblies A (Anwendung) und L (Library) werden gestartet und ein Typname, Namespace.Test, als String gespeichert, d.h. z.B.

Namespace.Test, M, Version=1.0.4467.38266, Culture=neutral, PublicKeyToken=null

Versuche ich nun, die Anwendung alleine zu starten, den String zu lesen und in einen Typ umzuwandeln (der sich in L befindet und zur Laufzeit geladen ist), wird nicht der richtige Typ gefunden. Selbst wenn ich den Loader zwinge, L zu verwenden, gibt er mir nicht den richtigen Typ zurück - warum, weiß ich nicht. Ich nehme an, dass es daran liegt, dass er obigen Typ sucht, aber den hier findet:

Namespace.Test, L, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Grüße
Dust Signs

16.07.2012 - 20:03 Uhr

Hallo!

Ich habe mehrere Typen, nennen wir einen davon einmal T, deren Namen als typeof(T).FullName (um später wieder die Assembly, aus der sie stammen, rekonstruieren zu können - Name alleine reicht hier nicht) gespeichert werden. Via Type.GetType kann ich dann später Informationen über den gespeicherten Typnamen bekommen, Instanzen erzeugen etc. So weit, so gut, wenn sich Assemblyname und -version nicht ändern.
Ändert sich die Version der Assembly, schlägt das Auflösen des Namens zu einem Typ fehl. Wie ich herausgefunden habe, kann ich hier Abhilfe schaffen, falls es ein Typ ist, dessen dazugehörige Assembly ich schon zur Compilezeit kenne (kommt in meinem Anwendungsfall glücklicherweise oft vor, wenn Abhängigkeiten bereits geladen sind), indem ich auf das AssemblyRevolve-Ereignis der aktuellen AppDomain reagiere:

            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(delegate(object obj, ResolveEventArgs args) //React on assembly resolving errors on changing library versions
            {
                return Assembly.GetAssembly(typeof(EinTypTDerBekanntIst)); //Try the library's current assembly (version)
            });

Das klappt soweit. Mein aktuelles Problem: wenn ich meine Libraries und mein Hauptprogramm mit ILMerge zusammenfüge und mit der zusammengefügten Assembly z.B. den Typ MergedAssembly.T (als String) speichere, liefert Type.GetType beim Starten der Anwendung alleine (d.h. mit externen Libraries) zwar ohne Exception einen Typ, doch verweist dieser "ins Nichts", d.h. er hat nicht die richtigen Attribute, implementiert keine Schnittstellen etc. Gibt es irgendeine Möglichkeit, in Type.GetType über ein anderes Ereignis oder eine Einstellung so einzugreifen, dass ich der Runtime dazu bewegen kann, die aus meiner Sicht korrekte, d.h. aktuelle, Assembly aus meinen Abhängigkeiten zu verwenden, ohne dass der Assemblyname dabei gleich wie die im String sein muss?

Danke im Voraus für eure Hilfe
Grüße
Dust Signs

07.03.2012 - 16:46 Uhr
o.GetType().GetGenericArguments()

, wenn o dein Objekt ist

Dust Signs

07.03.2012 - 07:48 Uhr

Das kann auch nicht funktionieren, da diese RegEx ja bedeutet, dass nach deinem Button-Namen (oder was auch immer dieser erste Textteil ist) kein Punkt kommen darf. Was du bräuchtest wäre eher so etwas:

\b[_]?(sp|ip|rp|bp|button)\w+(\.\w+)?$

oder

\b[_]?(sp|ip|rp|bp|button)\w+(\.\w+)*$

falls .Wert Unterwerte haben darf.

Dust Signs

06.03.2012 - 22:41 Uhr

Das Problem ist aus meiner Sicht der Zirkumflex (^). In einer eckigen Klammer (z.B.: [^A]) bedeutet er, dass die anderen Zeichen in der Klammer nicht vorkommen sollen (im genannten Beispiel das große A), in einer runden Klammer hat er eine andere Bedeutung (siehe Regex-Tutorial).

Dust Signs

06.03.2012 - 22:15 Uhr

Hallo!

Für dein unterstes Beispiel fehlt dir in der Regex die Berücksichtigung des Leerzeichens, wenn ich das richtig sehe.

Dust Signs

09.12.2011 - 21:14 Uhr

Hallo!

Wenn die Anzahl deiner Ressourcen klein ist und die einzelnen Threads nur weniger dieser Ressourcen beanspruchen, kannst du versuchen, (manuell) ein "Collission Array" zu erstellen, auf das du atomar zugreifst. Das Array hätte so viele Einträge wie du Ressourcen hast und der Wert an der i-ten Stelle des Arrays ist der aktuelle Thread (oder besser dessen ID o.ä.), der auf Ressource i zugreift. Du kannst dann in jedem Thread versuchen, die benötigten Ressourcen im "Collission Array" zuzuweisen (d.h. z.B. auf die Thread-ID zu setzen). Wenn das klappt, nimmst du dir die Ressourcen und schreibst nach deren Freigabe "0" oder einen anderen Dummy-Wert an die betroffenen Stellen im Array, damit die anderen Threads wissen, dass die Ressource wieder frei ist. Falls das Zuweisen einer Ressource nicht klappt, gibst du alle erfolgreich zugewiesenen frei (damit kein Deadlock entsteht) und versuchst es noch einmal (evtl. nach einer kurzen Wartezeit). Achtung: einzelne Threads (vor allem solche, die viele Ressourcen beanspruchen) können eventuell verhungern.
Die Implementierung des Zugriffs auf das Array wäre wahrscheinlich mit CAS günstig gelöst. Da ich momentan keinen Rechner mit VS bei der Hand habe, fällt mir nur obiger (prinzipieller) Ansatz ein. Vielleicht gibt es eine Frameworkklasse, die das bereits gekapselt anbietet, oder - noch besser - es gibt eine einfachere Lösung.

Dust Signs

25.09.2011 - 16:24 Uhr

Ok, schade eigentlich. Könnte ich vielleicht noch ein Attribut (auf A, B und C) so definieren, dass ich es irgendwie als Einschränkung nutzen kann? Soweit mir bekannt, ist das nur zur Laufzeit möglich, aber ginge das evtl. auch schon zur Designzeit, z.B. als Einschränkung eines generischen Typparameters?

Dust Signs

25.09.2011 - 15:36 Uhr

Das ist allerdings eine Idee. Gibt es hierbei eine halbwegs elegante Möglichkeit, vorzuschreiben, dass die gewünschte Klasse eine derartige statische Methode anbieten muss (per Interface ist das ja leider nicht möglich).

Dust Signs

25.09.2011 - 08:40 Uhr

wenn die Methode generisch ist, steht doch im Code an der Aufrufstelle dieser Methode der gewünschte Klassenname. Korrekt?

Korrekt.

Warum machst du dann DoSomething nicht generisch und rufst direkt das DoSomething der richtigen Klasse auf. Den Klassennamen hast du ja.

Ich habe momentan ca. 100 Klassen, deren DoSomething()-Methoden zwischen 5 und 50 Zeilen Code haben. Selbst mit einem generischen DoSomething muss ich diese Fallunterscheidung irgendwie durchführen, was die generische DoSomething()-Methode extrem unübersichtlich und unwartbar machen würde. Oder meintest du etwas anderes?

//In irgendeiner Helperklasse...
static void DoSomething<T>(...) where T : ABCBase
{
  ... //Fallunterscheidung für T
  return ...;
}

Dust Signs

25.09.2011 - 08:15 Uhr

Woher weißt du an dieser Stelle, welches DoSomething welcher Klasse aufgerufen werden muss.

Momentan ist die Methode, die aufgerufen wird, generisch. Je nach Typparameter wird dann entweder ein A, B oder C erzeugt, dessen DoSomething() aufgerufen und dessen Rückgabewert (auf T gecastet) zurückgegeben.
Die dafür benötigte Instanz erzeuge ich momentan über Reflection und werfe eine Exception, wenn es keinen parameterlosen Konstruktor gibt. Das ist natürlich hässlich, aber eine Zwischenlösung, bis ich etwas besseres gefunden habe. Dependency Injection, insbesondere Constructor Injection scheint da etwas zu sein, was durchaus hilfreich ist, aber erst recht wieder pro Klasse einen separaten Konstruktor erfordert, den man beim Erweitern der Klassenhierarchie nicht "vergessen" darf und der in den Kindklassen nicht zu erzwingen ist.

Dust Signs

24.09.2011 - 21:30 Uhr

Die Konstruktoren sind bereits teilweise public. Ein Beispiel:

public class A
{
  public A(int x, string y)
  {
    ... //Hier wird der interne Zustand von A anhand von x und y gesetzt
  }

  public ABCBase DoSomething()
  {
    A temp = new A(0, ""); //Insatz von A erzeugen, wobei die Parameter bewusst 0 und "" sind und damit eigentlich nicht gültig
    ... //Hier passiert etwas mit z, damit der interne Zustand von temp wieder gültig wird
    return temp;
  }
}

public class B
{
  public B(List<A> z)
  {
    ... //Hier wird der interne Zustand von B anhand von z gesetzt (Beispiel für eine komplexere Initialisierung)
  }

  public ABCBase DoSomething()
  {
    B temp = new B(null); //Insatz von B erzeugen, wobei der Parameter bewusst null und damit eigentlich nicht gültig ist
    ... //Hier passiert etwas mit z, damit der interne Zustand von temp wieder gültig wird
    return temp;
  }
}

Von außen ist es in Ordnung, Instanzen A und B mit den jeweiligen öffentlichen Konstrukturen zu erzeugen, da diese Instanzen dann immer einen gültigen internen Zustand besitzen.
Für meinen o.g. Anwendungsfall benötige ich aber spezielle Instanzen von A bzw. B, die temporär einen ungültigen Zustand haben können, da sie nachher wieder auf einen gültigen gesetzt werden. Ist DoSomething() in den Klassen selbst definiert (so wie oben), ist das übersichtlich, da jede Klasse selbst am besten weiß, welche Zustände gültig sind und welche nicht.
Würde ich eine Factory konstruieren, müsste ich für jede Klasse eine Fallunterscheidung machen. Würde ich die Konstruktoren direkt aufrufen, hätte ich dasselbe Problem an jeder Stelle, an der ich ein DoSomething aufrufe. Der Vollständigkeit halber sei erwähnt, dass DoSomething in meinem konkreten Fall nicht parameterlos ist, sondern einen Kontext als Parameter bekommt, aus dem die zu setzenden Werte ermittelt werden.

Dust Signs

24.09.2011 - 20:01 Uhr

Und warum benutzt du dann nicht generics?

Weil ich keine Instanz von A habe, von der ich DoSomething() aufrufen könnte.

Dust Signs

24.09.2011 - 18:59 Uhr

@herbivore: DoSomething() von A erstellt immer eine Instanz von A, DoSomething() von B immer eine von B u.s.w.
@Coder007: Dependency Injection muss ich mir noch genauer anschauen - danke vorerst für den Hinweis.

Dust Signs

24.09.2011 - 16:31 Uhr

Dann ist eine Factory wohl nichts für mich. Mir wäre es viel lieber, wenn jede Klasse selbst "wüsste", was zu tun ist und diese Funktionalität inkl. der Erzeugung einer Instanz irgendwie (z.B. als statische Methode) bereitstellt - das würde mir die Mühe ersparen, jede unterstützte Klasse in einer Factory zusammenzusammeln und eine Fallunterscheidung zu machen. Wenn später Klassen (oder ganze Klassenhierarchien) hinzugefügt werden, ist das ja ein Alptraum, was die Wartung angeht (von der Fehleranfälligkeit ganz zu schweigen).

Dust Signs

24.09.2011 - 15:40 Uhr

Nein, du brauchst nicht unbedingt eine Factory pro Klasse. Eine sollte reichen.

Wie aber soll diese Factory wissen, wieviele Parameter der jeweilige Konstruktur benötigt und welche Typen erwartet werden, ohne dass explizit für jede "unterstützte" Klasse eine Unterscheidung getroffen wird (was die Erweiterbarkeit sehr stark einschränkt)?

Dust Signs

24.09.2011 - 15:09 Uhr

Hallo!

Danke für deine Antwort. Wenn ich das Pattern (und das Beispiel hier) richtig verstanden habe, bräuchte ich dann aber eine Factoryklasse pro Klasse (eine für A, eine für B und eine für C), da DoSomething() für A, B und C verschieden aussieht. Das ist meiner Meinung nach ebenso unschön wie der Ansatz, eine statische Methode pro Klasse anzubieten.

Dust Signs

24.09.2011 - 13:03 Uhr

Hallo!

In einem Softwareprojekt stehe ich momentan vor einem Designproblem, das ich möglichst elegant lösen möchte. Vereinfacht gesprochen habe ich mehrere Klassen (nennen wir sie A, B und C - in Wirklichkeit sind es mehr, und die Namen sind nicht relevant; alle erben von ABCBase). All diese Klassen haben eine Methode DoSomething(), die eine spezielle Instanz von A, B bzw. C zurückliefert. Momentan sind diese Methoden nicht statisch und werden als Implementierung eines Interfaces (nennen wir es IABC) ausgeführt. So weit, so gut.

public class ABCBase
{
  //Nicht weiter wichtig
}

public interface IABC
{
  ABCBase DoSomething();
}

public class A : ABCBase, IABC
{
  ABCBase DoSomething()
  {
    A inst = new A();
    //... (Einige spezielle Operationen auf inst)
    return inst;
  }

  protected A()
  {
    //... (Nicht relevant)
  }
} //Klassen B und C analog

Nun gibt es aber einen Usecase, bei dem DoSomething() z.B. von A aufgerufen werden soll, ohne dass aber eine Instanz von A existiert.

ABCBase x = ... /* ? */; //Hier müsste eine Instanz von z.B. A erstellt werden, die nur für den Aufruf von DoSomething() benötigt würde
x = x.DoSomething(); //Hier wird nur der Rückgabewert von DoSomething gebraucht, x (von oben) wird eigentlich nicht benötigt

Theoretisch ist das kein Problem, denn ich kann DoSomething() ja statisch deklarieren. Das Problem ist nur, dass ich dann kein Interface mehr verwenden kann, das diese Funktionalität für A, B und C vorschreibt, sodass diese es implementieren müssen, da C# ja leider keine statischen Definitionen in Interfaces erlaubt.
Wie kann ich das nun sauber lösen? Ich habe mich bereits mit der Activator-Klasse (und deren CreateInstance-Methode) beschäftigt, doch haben einige meiner Klassen einen Konstruktur, der weder öffentlich, noch parameterlos ist. Gibt es eine schönere Lösung als ohne Interface jeder Klasse eine entsprechende statische Methode hinzuzufügen?

Danke für eure Hilfe
Grüße
Dust Signs

17.08.2011 - 09:05 Uhr

Kontextmenü -> Eigenschaften, Details?

Grüße
Dust Signs

30.09.2009 - 09:55 Uhr

Sorry, ich dachte, das war auf den Typ im Attribut bezogen. Da hab ich wohl wirklich nicht ordentlich gelesen. Die Schlussfolgerung bleibt dennoch die gleiche: ich werde wohl oder übel über Reflection einen eigenen Serializer implementieren müssen.

Dust Signs

30.09.2009 - 07:07 Uhr

Danke für eure Antworten. Ich habe gestern noch etwas experimentiert und gemerkt, dass ich im Prinzip vollständig auf einen eigenen Serializer angewiesen bin. Wenn ich nämlich ein Pen-Property habe, nutzt das ganze [XMLElement(typeof(MyPenWrapper))]-Attribut nichts, da sich zur Laufzeit der Serializer darüber beschwert, dass Pen über keinen parameterlosen Konstruktor verfügt. Damit bleibt mir wohl oder übel nichts anderes übrig, als mich tiefergehend mit Reflection zu beschäftigen.

Danke dennoch für eure Hilfe 😃
Dust Signs