2009-08-26 8 views
5

Wie einfach/schnell ersetzen Sie Floats für doubles (zum Beispiel) für die Kompilierung zu zwei verschiedenen Zielen mit diesen beiden besonderen Möglichkeiten der primitiven Typen?Wie wird ein primitiver Typ beim Kompilieren zu verschiedenen Zielen vorübergehend durch einen anderen ersetzt?

Diskussion: Ich habe eine große Menge an C# -Code in Entwicklung, die ich kompilieren muss, um abwechselnd float, double oder dezimals abhängig von dem Anwendungsfall der Zielbaugruppe zu verwenden.

Verwenden Sie etwas wie "Klasse MYNumber: Double", so dass es nur notwendig ist, eine Codezeile zu ändern, funktioniert nicht, da Double versiegelt ist, und natürlich gibt es keine # definieren in C#. Den Code mit #if #else Anweisungen pepping ist auch keine Option, es gibt einfach zu viel Unterstützung Math-Operatoren/verwandten Code mit diesen bestimmten primitiven Typen.

Ich weiß nicht, wie ich diese scheinbar einfache Aufgabe erledigen soll, danke!

Edit: Nur ein kurzer Kommentar in Bezug auf Boxing in Kyles Antwort erwähnt: Leider muss ich Boxen vermeiden, vor allem da Floats werden ausgewählt, wenn maximale Geschwindigkeit erforderlich ist, und Dezimalzahlen, wenn maximale Genauigkeit die Priorität ist (und die 20x + Leistungshit ist akzeptabel). Boxen würde wahrscheinlich Dezimalzahlen als eine gültige Wahl ausschließen und den Zweck etwas besiegen.

Edit2: Als Hinweis, dass Generika als mögliche Antwort auf diese Frage suggerieren, dass es viele Probleme gibt, die Generika auszählen (zumindest für unsere Bedürfnisse). Für eine Übersicht und weitere Referenzen siehe Using generics for calculations

+0

+1 Schöne Frage, viele verschiedene Lösungen wurden hier vorgestellt, die alle sehr ähnlich, aber dennoch interessant zu denken sind. Ich könnte dies jetzt in der Zukunft verwenden – LorenVS

Antwort

8

Der beste Weg, dies zu tun, wäre mit #if wie Andrew oben angegeben. Allerdings ist eine interessante Idee, darüber nachzudenken, etwas so sein würde:

#if USE_FLOAT 
using Numeric = System.Single; 
#endif 

#if USE_DOUBLE 
using Numeric = System.Double; 
#endif 

#if USE_DECIMAL 
using Numeric = System.Decimal; 
#endif 

public class SomeClass 
{ 
    public Numeric MyValue{get;set;} 
} 

EDIT:

ich noch mag diese Lösung ermöglicht es Ihnen, einige andere wirklich coole Dinge zu tun, wie zum Beispiel:

Numeric.Parse(); 
Numeric.TryParse(); 

, die für alle drei Typen

+0

Ich fing an, über eine Generics-Lösung nachzudenken, dann sah ich das. So einfach. Duh. – x0n

+0

Sieht gut aus, sehr einfach! Ich werde es versuchen und zurück zu dir ... – Keith

+0

Ja: Der einzige wirkliche Nachteil ist, dass Sie dieses Konstrukt in alle Ihre Dateien einfügen müssen; Dies wird jedoch dadurch aufgewogen, dass Sie auf diese Weise deklarierte Variablen so behandeln können, als würden Sie die ursprünglichen Typnamen verwenden. +1 –

0

Im schlimmsten Fall denke ich, Boxen und so etwas wie diese verwenden:

#if USE_FLOAT 
public float OutputValue(object input) 
{ 
    return (float)input; 
} 
#endif 

#if USE_DOUBLE 
public double OutputValue(object input) 
{ 
    return (double)input; 
} 
#endif 

und rufen OutputValue(1.5); es es für Sie zu konvertieren zu bekommen.

+0

Leider muss ich Boxen vermeiden, vor allem, da Floats ausgewählt werden, wenn maximale Geschwindigkeit erforderlich ist, und Dezimalstellen, wenn maximale Genauigkeit die Priorität ist und die 20x + Leistungseinbußen akzeptabel ist. Boxen würde wahrscheinlich Dezimalzahlen als eine gültige Wahl ausschließen. Danke für den Vorschlag - ich werde das in der Hauptfrage ansprechen. – Keith

0

Ein Ansatz wäre, ein Generikum um den Basistyp zu haben, den Sie benötigen. Dann deklarieren Sie eine Klasse, die eine bestimmte Instanz dieses Generics in einer separaten CS-Datei erbt, und Sie erstellen drei Kopien dieser Klasse für jeden benötigten Basistyp. Dann ändern Sie Ihre .csproj, um die richtige .cs-Datei basierend auf der Buildkonfiguration einzuschließen.

Beachten Sie, dass ich dies nicht wirklich versucht habe, also könnte es ein paar Knicke zum Ausbügeln geben.

0

Sie können dies tun:

public struct NumberContainer<T> 
{ 
    T _number; 

    // accessor, and possibly: operators, cast methods, etc. 
} 

Und dann:

#if USE_FLOAT 
public struct MyNumber : NumberContainer<float> 
#else 
public struct MyNumber : NumberContainer<double> 
#endif 
{ 
} 
+0

Uuuh ... Ich mag diese Lösung nicht, es verwandelt, was Sie normalerweise erwarten, ein Werttyp in einen Referenztyp. Gibt es einen Grund, warum Sie NumberContains eine Struktur nicht gemacht haben? – LorenVS

+0

Auch ist die Vererbungskette unnecssary wie Sie verwenden können: #if USE_FLOAT mit MyNumber = NumberContains #endif und dann machen NumberContainer nicht abstrakte – LorenVS

+0

Sorry, ja, eine Struktur besser wäre ... war Ich denke eher an das Hauptkonstrukt als an die Details. Bearbeitet. –

0

arbeiten Dies ist schwierig, da die Grundtypen nicht so etwas wie IArithmetic impelment.Dies wurde suggested many times on Connect. Leider ist dies eine well known limitation of generics.

Es gibt einige Problemumgehungen, die eine "calculator" struct class verwenden. Wenn die Mathematik nicht zu schwer ist, funktioniert das sehr, sehr gut.

Allerdings ist es klobig. Dies ist ein Ort, an dem Generika nicht so flexibel sind wie C++ - Vorlagen.

Ein anderer Ansatz könnte sein, etwas wie die Text Template Transformation Toolkit (T4) zu verwenden, um eine Vorlage zu generieren, die mit jedem Typ funktionieren würde, und separate Typen pro Typ zu kompilieren.