Autor Beitrag
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mi 10.12.14 16:11 
Hey,

ich stelle mir gerade die Frage, warum es (z.B. im .NET-Framework) Typen gibt, die sich über statische Funktionen instanziieren lassen, anstatt dafür einen Konstruktor zu verwenden. Spontan fällt mir da z.B. die Graphics-Klasse aus WinForms ein, welche die Funktion Graphisc.FromImage(einBild) anbietet. Warum wird sowas nicht in einen Konstruktor gepackt, also new Graphics(einBild);? Gibt es da irgendwelche Vorteile oder warum wird sowas gemacht?

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Mi 10.12.14 16:28 
Dahinter verbirgt sich meist eine Factory die für deine Anwendung die geeignete Bild-Klasse erzeugt.
Du könntest z.B. deine eigene Bildklasse (oder eine fremde) bei der Factory registrieren, die verbesserte Darstellung beim Zoomen liefert.
Deine ganze Anwendung profitiert davon, ohne eine Zeile im eigentlichen Quellcode zu ändern.
Selbst fremde Komponenten, die fertig vorliegen und eine Bild-Instance erstellen, müssen nicht verändert werden.

Für diesen Beitrag haben gedankt: C#
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 10.12.14 16:29 
Ich würde es machen um über die statische Methode eine Ableitung des zurückgegebenen Typs zu erzeugen von der der User nix genaues Wissen muß. Je nach Context liefert die Methode dann halt eine anderen Typ. Ich glaube bei Graphcs ist das aber nicht der Fall.

Für diesen Beitrag haben gedankt: C#
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mi 10.12.14 19:37 
@ Blub
Zitat:
Dahinter verbirgt sich meist eine Factory die für deine Anwendung die geeignete Bild-Klasse erzeugt.

Ja aber das kann doch genau so gut im Konstruktor passieren.
Color.FromArgb(...) fällt mir gerade noch als Beispiel ein.

@ Ralf
Verstehe ich dich richtig: du hast eine statische Methode in einer Klasse A. Diese Methode erzeugt - je nach Wert der Parameter - ein Objekt vom Typ B, welcher von A abgeleitet wird? Das würde dann aber bedeuten, dass die Basisklasse (A) alle Ableitungen kennen müsste (B). Außerdem wäre ja dann die Methode in einer anderen Klasse definiert.


Was macht es für einen Sinn wenn ich innerhalb der gleichen Klasse einmal einen Konstruktor habe um das Objekt zu erzeugen und einmal eine statische Methode die das gleiche Objekt erzeugt?
Noch ein Beispiel:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
 class Vector
    {
        public int X, Y;

        public Vector(int x, int y)
        {
            X = x;
            Y = y;
        }

        // Warum
        public static Vector FromPoint(Point p)
        {
            return new Vector(p.X, p.Y);
        }

        // statt
        public Vector(Point p) : this(p.X, p.Y)
        {
            
        }
    }

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Mi 10.12.14 20:23 
Dafür gibt es viele Gründe. Einer ist zum Beispiel die Philosophie "Konstruktorparameter ains essenziell für das Objekt und ohne diese Werte macht das Objekt einfach keinen Sinn". Darein fallen viele Sachen dann eben nicht, insbesondere viele FromXYZ Methoden. Sie bieten lediglich einen Weg an, Daten zu importieren.
Beispiel:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
    public static Hit FromProperty<T>(Expression<Func<T, object>> propertyExpression, string text)
      where T : class
    {
      var name = AttributeHelperMethods.GetPropertyDisplayName(propertyExpression);
      return new Hit(name, text);
    }

Die Methode ist generisch. Das ginge mit dem Konstruktor nicht, da nur der Konstruktor einer generischen Klasse generisch sein kann.
Vorteil: Am Naman der Methode ist direkt dokumentiert, welchen Zweck sie erfüllt. Stell' dir vor, es gäbe diese hier:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
Color.FromRGB()
Color.FromARGB()
Color.FromHSV()
Color.FromCMYK()
Color.FromCieLab()

Das kannst du gar nicht ordentlich mit Konstruktorparametern abbilden, da es alles 3-4 int-Werte sind.

Für diesen Beitrag haben gedankt: C#
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 10.12.14 21:09 
Zitat:
@ Ralf
Verstehe ich dich richtig: du hast eine statische Methode in einer Klasse A. Diese Methode erzeugt - je nach Wert der Parameter - ein Objekt vom Typ B, welcher von A abgeleitet wird? Das würde dann aber bedeuten, dass die Basisklasse (A) alle Ableitungen kennen müsste (B). Außerdem wäre ja dann die Methode in einer anderen Klasse definiert.


Die B's können im Zweifel auch irgendwas dynamisches sein was zur Compilezeit noch gar nicht bekannt ist (z.B. weil es ein Plugin System ist). Aber man braucht natürlich einen Ansatzpunkt um an konkrete Klassen zu kommen ohne die konkret zu kennen. Da ist eine Create Methode an einer Basisklasse ein möglicher Weg.

Solche Create Methoden sind ein übliches Muster im Framework (ohne dabei irgendwas mit Plugins zu tun zu haben) Beispiele :

- Delegate.CreateDelegate (liefert MulticastDelegate)
- Array.CreateInstance (liefert konkretes Array abhängig vom übergebenen Typ)
- im Cryptography Namespace haben eigentlich alle Basistypen eine Create Methode der man den konkret gewünschten Algo (der eine Ableitung der Basisklasse darstellt) mitgeben kann

Zitat:
Ja aber das kann doch genau so gut im Konstruktor passieren.
Color.FromArgb(...) fällt mir gerade noch als Beispiel ein.


Ein Konstruktor hat wie jfheins nebenbei aufzeigt extrem schlechte dokumentarische Eigenschaften. Gerade bei Color ist es eben nicht genauso lesbar machbar. Da Graphics eine ganze Reihe von FromXXX Methoden hat mag das dort auch ein Grund sein.

Meine Theorien nach 2.ter Überlegung bezüglich Graphics ist eine andere ;)
Die Methode hat erst im 2.0er Framework Einzug gehalten so wie die anderen FromXXX Methoden. Die 1er Philosophie von Graphics ist aber vermutlich das man die nicht selbst erzeugen können soll.
Ein Graphics Object macht ja auch isoliert keinen Sinn es ist immer nur ein Wrapper um einen GDI Context der an einem Control hängt und man holt sich den vom Control (Control.CreateGraphics) und erzeugt den eben nicht selber. Das man den auch für ein Image gebrauchen kann ist denen dann erst später eingefallen da stand die Philosophie aber schon. Beim Designermeeting Graphics.FromImage vs. Image.CreateGraphics hat sich dann erstere Partei durchgesetzt. Die Überlegung könnt aber auch nur eine Verschwörungtheorie sein ;)
Worauf ich hinaus will im Rückblick auf ein Design ist es leicht historische Notwendigkeiten (ich wage es nicht da von Schwäche zu sprechen über die Stabilität der Designphilisophie der ursprünglich erdachten Muster kann ich nur staunen) zu übersehen die sich oft nur den direkt Beteiligten erschließen. Wir können nur hoffen das ein paar Microsoft Insider in ihren Blogs über solche Details schreiben und uns den Entstehungsweg eines Features im Framework aufzeigen.

Für diesen Beitrag haben gedankt: C#
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mi 10.12.14 23:42 
Ja das leuchtet ein. Vielen dank Euch.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler