Gibt es eine "StringToEnum"-Funktion oder eine Alternative? - Seite 3

 
cyberglassed:

Ihr obiger Code ist nutzlos, weil er immer "b = 0" zurückgeben wird.

und die Info: "b = 0" gibt jedes Mal keine Informationen.

Nein, es gibt 3 zurück.


oder die letzte, auf die er trifft.

Ich schätze, du hast mich falsch verstanden.

sinput string e_string="MODE_SMMA";// Input Ma Method

int b;
if(e_string==EnumToString(MODE_SMA)){b=0;}
if(e_string==EnumToString(MODE_EMA)){b=1;}
if(e_string==EnumToString(MODE_SMMA)){b=2;}
if(e_string==EnumToString(MODE_LWMA)){b=3;}

Print(b);
 

Habe ich das richtig verstanden? Sie beginnen mit einer Zeichenkette ??

man kann sie auch einpacken ()

int b;
sinput string e_string;// Input Ma Method here AS A STRING 

void OnTick(){StringToEnum();Print(b);} 
  
void StringToEnum()
 {
 if(e_string==EnumToString(MODE_SMA)){b=0;}
 if(e_string==EnumToString(MODE_EMA)){b=1;}
 if(e_string==EnumToString(MODE_SMMA)){b=2;}
 if(e_string==EnumToString(MODE_LWMA)){b=3;}
 }

aber man muss sicherstellen, dass die Zeichenkette aus offensichtlichen Gründen genau übereinstimmt, sonst braucht man mehr Code, um sicherzustellen, dass es nicht schief geht.

 
Marco vd Heijden:

nein sie gibt 3 zurück.

oder die letzte, der sie begegnet.

Ich glaube, Sie haben mich falsch verstanden.

ja, nachdem ich meinen Kommentar geschrieben habe, habe ich bemerkt, dass du kein "else if" benutzt hast und ich habe es auf 3 geändert

Marco vd Heijden:

habe ich das richtig verstanden? man beginnt mit einer zeichenkette ??

man kann sie auch einpacken ()

aber Sie mussten sicherstellen, dass die Zeichenkette aus offensichtlichen Gründen eine exakte Übereinstimmung ist, sonst ist mehr Code erforderlich, um sicherzustellen, dass es nicht schief geht.

Ja, ich beginne mit einer Zeichenkette, deshalb ist die Signatur der Funktion, die ich vorschlage, so:

int StringToEnum(string strId);

Wie auch immer, wie wir alle analysiert haben, ist die einzige Abhilfe, die wir bis jetzt haben, die Verwendung von mehreren "if" ;)

 

"Dann wollen Sie an einer Stelle einen Wert einer Aufzählung im String-Format angeben."

Ich sehe darin keinen Vorteil. Könnten Sie ein Beispiel zeigen?


Methode 1:

int StringToEnum(string strId) {         if (false) {}         else if (strId == "PRICE_CLOSE")     return 1;         else if (strId == "PRICE_OPEN")      return 2;         else if (strId == "PRICE_HIGH")      return 3;         else if (strId == "PRICE_LOW")       return 4;         else if (strId == "PRICE_MEDIAN")    return 5;         else if (strId == "PRICE_TYPICAL")   return 6;         else if (strId == "PRICE_WEIGHTED")  return 7;         // ...         return -1; } void OnStart() {         string strId = "PRICE_MEDIAN";         printf("%s: %d ", strId, StringToEnum(strId)); }

Methode 2:

void OnStart() {
        ENUM_APPLIED_PRICE b=PRICE_MEDIAN;
        
        printf("%s: %d ", EnumToString(b), b);
}

Sie müssen in beiden Fällen nur den String-Namen des Enums kennen. Außerdem ist Ihr Code falsch, da die Aufzählung bei 0 beginnt.


 
cyberglassed:

Hallo Alain, ich befriedige deine Neugierde :P

Stell dir vor, du verwendest mehrere externe mql5-Codes, dann hast du es mit mehreren "enum"-Datentypen zu tun, die darin definiert sind, und natürlich ist es für dich, wie für einen Menschen, besser, dir den String-Namen jedes Wertes jedes "enum" zu merken. Wenn Sie dann an einer Stelle einen Wert eines "enum" im String-Format angeben wollen, können Sie das nicht direkt tun, sondern müssen eine Umgehung verwenden, wie ich oben geschrieben habe. Dies hat zwei große Nachteile: Der erste ist, dass man alle Werte aller beteiligten Enums sammeln muss, und der zweite Nachteil ist die Wartung. Wenn man also einen externen mql5-Code aktualisiert, bei dem der Entwickler den mit einer Konstanten verknüpften int-Wert geändert hat, kann es zu unerwartetem Verhalten kommen, so dass man immer wieder nach Updates des Codes suchen muss.

Danke, aber das ist nicht wirklich das, wonach ich gefragt habe. Können Sie ein konkretes Code-Beispiel nennen?

Ich bin mir zu 100 % sicher, dass alle Ihre Argumente zur Funktion StringToEnum() auf eine schlechte Programmierpraxis zurückzuführen sind. Das Ziel eines Enums ist es, Code unabhängig vom zugrundeliegenden Integer-Wert zu erstellen, wenn dieser Wert geändert wird, sollte das keine Auswirkungen auf Ihren Code haben. Ich verstehe auch nicht, warum man sich einen Bezeichner wie MODE_SMA nicht merken kann, aber mit einer Zeichenkette "MODE_SMA".

Zum Thema Sicherheitsleck... Ich bin nicht ganz einverstanden mit dem, was Sie sagten, dass es eine offene Tür für Sicherheitslecks ist. Natürlich könnte es eine offene Tür sein, aber als Programmierer muss man die Grenzen setzen und sich um mögliche kritische Situationen kümmern, ich meine, man kann solche Situationen perfekt handhaben, wie in PHP, sogar bei SQL mit Code-Injektion, wo man einige kritische mögliche Eingabedaten von Benutzern parsen muss, falls sie Zugriff auf Ihren Code haben.

Ich habe nicht gesagt, dass die Sicherheit nicht vom Programmierer verwaltet werden kann. Ich sagte, dass Metaquotes diese Sicherheit nicht von den Programmierern abhängig machen wird. Das wird nie passieren, ich schlage vor, Sie fragen sie, indem Sie eine Anfrage an den ServiceDesk stellen, ich kenne die Antwort bereits.

 
cyberglassed:

ja, nachdem ich meinen Kommentar geschrieben habe, ist mir aufgefallen, dass du kein "else if" benutzt hast und ich habe es in 3 geändert

ja, ich gehe von einer Zeichenkette aus, deshalb lautet die Signatur der Funktion, die ich vorschlage:

wie auch immer, wie wir alle analysiert haben, ist die einzige Abhilfe, die wir bis jetzt haben, die Verwendung von mehreren "if" ;)


ja, aber man kann das auch in einer Schleife und in nur einer Zeile machen.

 //string in="MODE_SMA";  //uncheck either one
 //string in="MODE_EMA";
 string in="MODE_SMMA";
 //string in="MODE_LWMA";    

void OnTick()

{
 int out;
 
 for(int i=0;i<=3;i++){ENUM_MA_METHOD mode=i;if(in==EnumToString(mode)){out=i;Print("out: ",out);}} 
}


aber immer noch nach fast 4 Seiten ... whyyyy haha :)

 
Marco vd Heijden:

ja, aber man kann das auch in einer Schleife und in nur einer Zeile machen.

aber immer noch nach fast 4 Seiten ... whyyyy haha :)

Laszlo Tormasi:

"Dann will man an einer Stelle einen Wert einer Enum im String-Format angeben."

Ich sehe keinen Vorteil darin. Könntest du ein Beispiel zeigen?

Sie müssen in beiden Fällen nur den Stringnamen des Enums kennen. Außerdem ist Ihr Code falsch, denn die Aufzählung beginnt bei 0.

hahaha Marco und Laszlo sorry, manchmal, wenn man versucht, das Problem zu minimieren, steigt die Neugier auf der anderen Seite :P

hier habt ihr ein sehr nahes Beispiel für das, was ich erreichen möchte (ich habe es ein wenig verkleinert, um euch nicht zu verärgern). Das Folgende ist ein komplettes funktionierendes Skript (kopieren/einfügen/ausführen):

string get_price_type() {
        string
                config_url = "http://tempsend.com/D56DA3A9EA/CBB5/config.txt", /* available for 30 days from now */
                cookie = NULL,
                headers,
                ret;
        char
                post[],
                result[];               

        // WebRequest needs the following configuration:
        // 1- check: Tools/Options/Expert Advisors/Allow WebRequest for listed URL
        // 2- add url: http://tempsend.com  [this is the domain name on: config_url]
        int res = WebRequest("GET", config_url, cookie, NULL, 5000,  post, 0, result, headers);
        
        if (res == -1) {
                Print("Error in WebRequest. Error code: ", GetLastError());
                ret = "Error";
        }
        else {
                ret = CharArrayToString(result);
                StringTrimRight(ret);
        }
        return ret;
}

int StringToEnum(string strId) {
        if (false) {}
        else if (strId == "PRICE_CLOSE")     return 1;
        else if (strId == "PRICE_OPEN")      return 2;
        else if (strId == "PRICE_HIGH")      return 3;
        else if (strId == "PRICE_LOW")       return 4;
        else if (strId == "PRICE_MEDIAN")    return 5;
        else if (strId == "PRICE_TYPICAL")   return 6;
        else if (strId == "PRICE_WEIGHTED")  return 7;
        return -1;
}

void OnStart() {
        string price_type = get_price_type();
        int price_type_int = StringToEnum(price_type);
        printf("price_type -> %s: %d", price_type, price_type_int);
        
        ChartSetInteger(0, CHART_SCALE, 3);
        ChartSetInteger(0, CHART_MODE, CHART_CANDLES);

        int handle = iMA("EURUSD", PERIOD_CURRENT, 10, 0, MODE_SMA, price_type_int);
        ChartIndicatorAdd(0, 0, handle);
}

Die Art des Preises wird in der Online-Datei festgelegt, die auf: "config_url" und sein Inhalt kann jederzeit mit einem der folgenden Werte geändert werden:

{PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED}

Der Typ wird in menschenlesbarer Form angegeben, zum Beispiel: PRICE_MEDIAN (kein int).

Laszlo, bei mql5 ist der Offset 1 und nicht 0 (anders als bei mql4), ich habe es mit einem einfachen Skript überprüft und war überrascht. Deshalb spreche ich über das Problem der Wartung -> mögliche Verwechslungen.
 
Alain Verleyen:

Danke, aber das ist nicht wirklich das, wonach ich gefragt habe. Können Sie ein konkretes Code-Beispiel posten?

Ich bin mir zu 100% sicher, dass alle Ihre Punkte über die StringToEnum()-Funktion auf eine schlechte Programmierpraxis zurückzuführen sind. Das Ziel eines Enums ist es, Code unabhängig vom zugrundeliegenden Integer-Wert zu erstellen, wenn dieser Wert geändert wird, sollte das keine Auswirkungen auf Ihren Code haben. Ich verstehe auch nicht, warum man sich einen Bezeichner wie MODE_SMA nicht merken kann, aber mit der Zeichenkette "MODE_SMA" schon.

Ich habe nicht gesagt, dass die Sicherheit nicht vom Programmierer verwaltet werden kann. Ich sagte, dass Metaquotes diese Sicherheit nicht von den Programmierern abhängig machen wird. Das wird nie passieren, ich schlage vor, Sie fragen sie, indem Sie eine Anfrage an den ServiceDesk stellen, ich kenne die Antwort bereits.

Ich habe mich geirrt, und ich weiß, dass ich eine StringToEnum()-Funktion benötige (die nicht für jede Aufzählung codiert werden muss). Es ist nie zu spät zu verstehen, ich sollte nie 100% sicher sein.

 
Alain Verleyen:

Ich habe mich geirrt und ich weiß, dass ich eine StringToEnum()-Funktion benötige (generisch, nicht für jede Aufzählung zu codieren). Es ist nie zu spät zu verstehen, ich sollte nie 100% sicher sein.

Hier ist eine generische StringToEnum() Funktion:

#define MIN_ENUM_VALUES 0
#define MAX_ENUM_VALUES 255
//+------------------------------------------------------------------+
//| StringToEnum : Convert a string to an ENUM value,                |
//|   it loop between min(0) and max(255), adjustable if needed.     |
//|   Non existing enum value defined as -1. If -1 is used as an     |
//|   enum value, code need to be adjusted to an other default.      |
//| Parameters :                                                     |
//|   in       - string to convert                                   |
//|   out      - ENUM value                                          |
//|   @return  - true if conversion succeed, false otherwise         |
//+------------------------------------------------------------------+
template<typename ENUM>
bool StringToEnum(string in,ENUM &out)
  {
   out=-1;
//---
   for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++)
     {
      ENUM enumValue=(ENUM)i;
      if(in==EnumToString(enumValue))
        {
         out=enumValue;
         break;
        }
     }
//---
   return(out!=-1);
  }

Verwendungsbeispiel :

//+------------------------------------------------------------------+
//| testing enums                                                    |
//+------------------------------------------------------------------+
enum ENUM_TEST
  {
   FIRST_CASE=1,
   SECOND_CASE=2

  };
//---
enum ENUM_ANOTHER_TEST
  {
   CASE_ONE,
   CASE_TWO,
   CASE_THREE
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void  OnStart()
  {
   ENUM_TEST which;
   if(!StringToEnum("SECOND_CASE",which)) return;

   ENUM_ANOTHER_TEST which_other;
   if(!StringToEnum("CASE_ONE",which_other)) return;

   ENUM_TEST wrongwhich;
   if(!StringToEnum("blah blah",wrongwhich)) return;

//---
  }
 
Alain Verleyen Funktion:

Verwendungsbeispiel :

4,5 Jahre später, aber ich bin auf diesen Beitrag gestoßen, als ich nach einer Lösung für diesen Bedarf suchte. @Alain Verleyen Es freut mich, dass Sie eine Anwendung gefunden haben, die Ihren anfänglichen Antworten "Ich weiß nicht, warum wir das brauchen" und "Wenn Sie diese Funktion brauchen, dann ist Ihr Code schlecht" entgegenwirkt 😛.

Ich bin auf eine Reihe verschiedener Umstände gestoßen, unter denen dies nützlich wäre, aber selbst wenn weder Sie noch ich einen Bedarf gefunden hätten, stellt sich die Frage: Wenn es keinen Grund für StringToEnum() gibt, warum sollte es dann einen Grund für EnumToString() geben? Oder umgekehrt, wenn es EnumToString() gibt, dann ist es doch nicht unvernünftig zu denken, dass es Zeiten geben könnte, in denen wir eine Enum in eine Zeichenkette konvertieren, indem wir diese Funktion benutzen, und sie dann manchmal wieder zurück konvertieren wollen 😉 .

Unnötig zu erwähnen, dass mein praktisches Beispiel: Ich habe einen EA, der auf mehreren Symbol/Zeitrahmen-Kombinationen gleichzeitig arbeitet, unabhängig von dem Chart, auf dem er läuft - ohne ihn auf mehreren Charts gleichzeitig laufen lassen zu müssen. Dieser Ansatz hat seine Vor- und Nachteile, aber in meinem Fall überwiegen die Vorteile eindeutig die Nachteile.

Wenn ich also einen Trade platziere, möchte ich in den Kommentaren des Trades ein paar Details sehen, die die Trade-Info-Funktionen nicht bieten. Eines davon ist der Zeitrahmen, der verwendet wurde, um die Logik zu bestimmen, ob der Trade überhaupt platziert werden soll, da diese Logik (die zum Teil vom Zeitrahmen abhängt) sich manchmal darauf auswirkt, wann der Trade modifiziert (z. B. SL) oder geschlossen werden soll. Ich möchte diese Informationen also in einer für Menschen lesbaren Form sehen (z. B. H4, nicht 14400), aber natürlich möchte ich auch, dass der EA den numerischen Enum-Wert verwenden kann, wenn er Entscheidungen über die Änderung oder Schließung des Handels trifft.

Also verwende ich EnumToString(timeframe), um eine String-Darstellung des Zeitrahmens im Kommentar zu haben. Später kann ich dann den Kommentar aus dem Handel mitOrderComment() (oder der entsprechenden mql5-Version) abrufenund kann dann die String-Darstellung des Zeitrahmens aus dem Kommentar auslesen, um z. B. "PERIOD_H4" zu erhalten. Eine StringToEnum("...")-Funktion würde das zurück in den numerischen Wert konvertieren, der im Fall von Timeframes die Anzahl der Minuten ist (d. h. die Aufzählung ist nicht sequentiell von 0 bis etwas wie die meisten Aufzählungen, es gibt große Lücken, z.B. zwischen D1, W1 und MN1). Natürlich könnte ich auch den Integer-Wert der Aufzählung in den Kommentar einfügen, aber das ist eine (eigentlich unnötige) Umgehung des Fehlens von StringToEnum().

Ihre Lösung scheint so gut zu sein, wie es im Moment geht, außer dass wir in diesem Fall den MAX-Wert auf43200 erhöhen müssten, um umfassend genug zu sein, um das abzudecken und gleichzeitig generisch zu bleiben(https://docs.mql4.com/constants/chartconstants/enum_timeframes).

Natürlich würde eine OrderTimeframe()- oder OrderPeriod()-Funktion diesen speziellen Bedarf decken, aber wie gesagt, das ist nur einer von wenigen Fällen, in denen eine StringToEnum()-Funktion hilfreich wäre. Anscheinend haben Sie auch eine gefunden 😉 .

Danke, dass du deine Lösung mit uns geteilt hast. Und Hut ab vor deiner Bescheidenheit, zuzugeben, dass du falsch lagst 😊.

Ich frage mich, ob es irgendwo in der MQL4/5-Dokumentation eine Liste aller möglichen Enums und Enum-Werte gibt. Es gibt diese Seite:https://www.mql5.com/en/docs/constant_indices und die entsprechende mql4-Version dieser Seite, obwohl dort keine numerischen Werte aufgeführt sind. Ich nehme an, ich könnte den Text dieser Seite kopieren, ihn in eine Liste der Werte zerlegen und eine Funktion schreiben, die alle möglichen Werte ausgibt. Aber das ist natürlich etwas mühsam und berücksichtigt auch keine zukünftigen Ergänzungen. Zumindest kann ich so den maximal möglichen Wert jeder Enum ausgeben.

Um Geschwindigkeit zu sparen, könnte ich Ihre Funktion wahrscheinlich so anpassen, dass sie eine Schleife durch alle Werte bis zu einem Maximalwert von, sagen wir, 1440 anstelle von 256 durchläuft (für D1 im Fall von Timeframes und was auch immer im Fall anderer Enums), und dann zwei spezifischere Überprüfungen für W1 und MN1 hinzufügen. Die Erhöhung des Maximalwerts würde keinen zusätzlichen Aufwand für alle Fälle bedeuten, die immer noch in den unteren Maximalwert passen würden, da alles, was unter den unteren Maximalwert passt, so oder so in derselben Zeit aus der Schleife herauskommt.

Gibt es andere Enums mit numerischen Werten, die höher als 1440 gehen?

Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
  • docs.mql4.com
Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
Grund der Beschwerde: