C# struct abstract
Wie kann ich erreichen, Vererbung (oder ähnlich) mit structs in C#?
Ich weiß, dass eine abstrakte Struktur nicht möglich ist, aber ich brauche etwas erreichen ähnlich.
Ich brauche es als eine Struktur, weil es einen Wert geben. Und ich brauche Vererbung, denn ich brauche einen generischen array und Methoden, die ich kann garantieren, gibt es.
Ich denke, ein Beispiel wird einen langen Weg gehen, hier sind einige code, der nicht kompiliert wird, aber zeigt, was ich erreichen will;
abstract struct Vertex
{
abstract int SizeInBytes;
abstract void SetPointers();
}
struct ColorVertex : Vertex
{
Vector3 Position;
Vector4 Color;
override int SizeInBytes //static
{
get { return (3 + 4) * 4; }
}
override void SetVertexPointers() //static
{
...
}
}
class main
{
static void main()
{
Vertex[] verts = new Vertex[3];
for(int i = 0; i < 3; i++)
verts[i] = new ColorVertex();
verts[0].SetVertexPointers(); //should call ColorVertex.SetVertexPointers
externalAPIcall(verts);
}
}
EDIT:
Den Grund brauche ich Wert-Typen ist so, dass ich ein array von Ihnen, und übergeben es an OpenGL als vertex-buffer. Für die Daten, die benötigt werden, direkt enthalten, in das array.
Ich würde sein überrascht, wenn diese waren einfach nicht möglich, zu erreichen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Im Licht Ihrer kürzlichen edit:
Scheint es, wie die real Lösung für Sie ist die Kapselung. Wenn Sie das layout Ihres
struct
ist diktiert von einem third-party-API (so dass Sie interagieren können mit unmanaged code), dann sollte man sich wirklich überlegen, das einwickeln der API-Typen in den entsprechenden Klassen, anstatt zu versuchen, mit Ihnen zu interagieren, direkt in den code.Für ein, Sie sagen:
Dies ist nicht das entpuppen, was Sie erwarten. Wie andere haben darauf hingewiesen, daß die einzige Möglichkeit zur Festlegung einer Reihe von gemeinsamen Funktionen anwenden können, um Strukturen ist durch Schnittstellen (zum Beispiel, die primitiven Datentypen in .NET implementieren
IComparable
). Leider, wenn Sie deklarieren ein array vom TypIYourInterface
alle Werte erhalten boxed (interface-Referenzvariablen Referenztypen, selbst wenn der zugrunde liegende Wert Sie sind, zeigen auf, sind Wert-Typen).Zum Beispiel, sagen wir, Sie erklären eine
IVertex
Schnittstelle:Haben, und Sie haben ein oder mehrere Wert-Typen, die es umzusetzen:
Wann immer Sie dies tun:
Die zweite Zeile Feld den Wert
myVertex
und speichern Sie einen Verweis auf die boxed-Wert infoo
. Da arrays sind nur eine Reihe von Variablen gelten die gleichen Regeln:Alle Werte in
foos
wird boxed und Referenzen gespeichert. Dies ist anders, als wenn du es getan hast:Wo keine Boxen notwendig ist.
Dies hat Konsequenzen, die in direktem Zusammenhang zu dem, was Sie suchen sind, als Boxen die Werte nun bedeutet, dass Sie nicht mehr ein zusammenhängender block von Werten (gut, Sie tun, aber der zusammenhängenden block ist nur Verweise; die Werte selbst liegen anderswo).
Kapselung
Angesichts der Tatsache, dass Sie
Sollten Sie sich wirklich überlegen, das einwickeln der OpenGL-API. Zum Beispiel, sagen wir, dass Sie Folgendes haben:
Was ist wahrscheinlich eine bessere option wäre, um zu definieren, Ihre eigene Schnittstelle zu, dann verstecken Sie die OpenGL-API:
(Das ist natürlich ein erfundenes Beispiel, aber es sollte zeigen, was ich versuche zu vermitteln in Bezug auf die Einführung einer Abstraktionsschicht zwischen Ihrem code und die andere API)
T returnSmaller<T>(ref T p1, ref T p2) where T:IComparable<T> {return p1.CompareTo(p2) < 0 ? p1 : p2;}
(ich haberef
Parameter zu eliminieren, ein paar extra-struct-copy-Operationen, obwohl einige immer noch benötigt wird; es gibt keine Boxen in jedem Fall).In C#, können Sie Schnittstellen zu erreichen, so etwas wie Polymorphismus mit Werttypen (structs) als können Sie nicht ableiten, das direkt von einem
struct
aber Sie können mehrerestruct
Typen implementieren bestimmte Schnittstellen.Daher, statt Ihr abstract
struct
,Vertex
haben, können Sie eine SchnittstelleIVertex
.Ist es jedoch überaus selten, dass Sie brauchen, um Ihre eigenen Wert-Typen, so stellen Sie sicher, dass Sie wirklich brauchen, Wert Typ Semantik, bevor Sie fortfahren. Wenn Sie das tun, setzen Sie Ihre eigene Werte-Typen, stellen Sie sicher, Sie sind unveränderlich als veränderliche value-Typen sind ein gateway, um alle Arten von schrecklichen Problemen.
Sollten Sie sich bewusst sein, dass die Boxen auftreten wird bei der Umwandlung von einem Wert, der den Typ einer Schnittstelle. Dies hat nicht nur Auswirkungen, wenn Ihr Wert Arten sind veränderlich (machen Sie nicht änderbarer Wert-Typen), aber das wird sich verringern, oder die meisten wahrscheinlich Abbrechen Speicher Vorteil, Sie können gewinnen mit einem Wert hat, je nachdem, Wann oder wie Sie dies tun und ob Sie für jeden Wert einen profiler verwenden, wenn Sie sich nicht sicher sind.
Kann man nicht, im Grunde. Können Sie nicht ableiten, aus einer struct. Warum denken Sie, dass Sie möchten, dass ein struct statt der Klasse? Sie sagen: "es muss einen Wert geben" - warum? Ebenfalls denken Sie, Vererbung ist die einzige option, die anstelle von (sagen wir) Zusammensetzung? Zum Beispiel könnten Sie verwenden:
Du bist einfach nicht in der Lage sein, um eine "abstrakte Struktur" oder etwas ähnlichem zu arbeiten, so dass ich schlage vor, Sie erklären die Gründen hinter Ihre Anforderungen unerfüllbar, anstatt nur unter Angabe Sie als Anforderungen, die nicht vermieden werden können.
Vertex[]
wird es am Ende Boxen einen beliebigen Wert Hinzugefügt, die man wahrscheinlich entfernen Sie die Hälfte der Punkt der Verwendung von structs überhaupt.Unter-geschätzt-Funktion von Werttypen in .net ist, dass Sie übergeben werden können, wie - Schnittstelle-eingeschränkte generische Typen ohne Boxen. Zum Beispiel:
Beachten Sie, dass ich verwendet
ref
Parameter zu beseitigen, wodurch zusätzliche temporäre Kopien der beiden Parameter; eine zusätzliche Kopie desp2
am Ende wird gemacht, wenn Sie übergeben werden, um dieCompareTo
Methode, und mindestens eine zusätzliche Kopie wird wahrscheinlich gemacht werden, wenn das Ergebnis zurückgegeben wird, sondern darum, dass zwei redundante Kopien wären besser als vier. In jedem Fall, die oben genannten Methode kann aufgerufen werden, ohne Boxen, die auf jede ArtT
implementiertIComparable<T>
.Leider gibt es keine furchtbar nette Art zu sagen, "wenn
T
ist eine Art von Struktur, übergeben Sie es an eine Methode, die Einstellungen, geben; andernfalls, wenn es eine andere geben, übergeben Sie es an eine Methode und nehmen". So, code erfordert eine genaue spezifische Klasse (wie z.B. den code mithilfe der API ' s), werden Sie wahrscheinlich haben, um nicht-generische. Dennoch, wenn es gibt einige Methoden, die sollte verwendbar sein, die auf einer Vielzahl von Strukturen, diese Strukturen interfaces implementieren und dann übergeben Sie als eingeschränkt generische Typen bieten einige große Vorteile.Können Sie Schnittstellen
Sieht es aus wie das, was Sie wollen, ist eine Schnittstelle.
Einer Schnittstelle Sinn macht, da alle Ihre Methoden als abstract deklariert (dies würde bedeuten, es beruht auf der Ableitung von Klassen um die Methode zu implementieren, die im wesentlichen ist, was ein interface ist)
Können Sie erstellen, die Schnittstelle IVertex und dann hinzufügen, um Ihre Strukturen.
Vielleicht können Sie ein "union" Typ:
Nur daran erinnern, um es unveränderlich und nur den Zugriff auf die Felder, die sinnvoll für jeden Typ.
Klassen "Wert-Typen" als gut (im Sinne von Domain-Driven Design). Alles, was Sie tun müssen, ist es unveränderlich, machen die Konstruktoren unzugänglich öffentlich (Protected oder internal), und erstellen Sie statische factory-Methoden, um Instanzen zu erstellen und Sie zu kontrollieren, Ihre Instanziierung und haben keine Set-Methoden auf Ihre Eigenschaften...
HINWEIS: Der Satz Wert Typ in diesem contect hat nichts zu tun mit dem Wert Typ vs Typ der Referenz. Es hat zu tun mit Wert Typ vs Entity-Typ wie in der Domäne Drtiven Design oder Domain Modeling...
struct
. Ich glaube nicht, dass eine Verwechslung der OP durch die Annahme eines alternativen Vokabulars hilfreich ist.struct
Arten.struct
bedeutet (es gibt keinen Grund, es muss einstruct
wenn es ist eine Frage, die einfach erfordern Unveränderlichkeit), anstatt eine einfache überflüssige Anweisung. Sie reden über einen einzigen Satz, der tangential zu dem eigentlichen Kern der Frage ist also, ob oder nicht es möglich ist, verwenden Sie Vererbung mit Wert-Typen.