Benutzer mit den meisten Antworten
Probleme mit generics und dynamic

Frage
-
Hallo zusammen,
bei der folgenden generischen Funktion gibt es beim Übersetzen Fehlermeldungen für Zeilen die 'var sum = (T)0' und 'sum += arr[i + n] * filter[n]' => "Eine Konvertierung vom Typ "int" in "T" ist nicht möglich." und "Der Operator "*" kann nicht auf Operanden vom Typ "T" und "T" angewendet werden." Soweit ich das gelesen habe, gibt es keine Möglichkeit mit 'where T : ...' T auf Wertetypen zu beschränken.
public static T[] ConvolutionOn1DimArr<T>(T[] arr, T[] filter, int? centerIndex = null, T? borderValue = null) where T : struct { if (arr == null || filter == null) return arr; if (centerIndex == null) centerIndex = filter.Length / 2; if (centerIndex < 0 || centerIndex >= filter.Length) throw new IndexOutOfRangeException("Das Zentrum des Filters liegt ausserhalb des gültigen Bereichs"); var first = arr.Take(centerIndex.Value).Select(v => borderValue == null ? v : borderValue.Value); var last = arr.Skip(arr.Length - filter.Length + centerIndex.Value + 1).Select(v => borderValue == null ? v : borderValue.Value); var center = arr.Skip(first.Count()).Take(arr.Length - first.Count() - last.Count()).Select((v, i) => { var sum = (T)0; for (int n = 0; n < filter.Length; n++) sum += arr[i + n] * filter[n]; return sum; }); return first.Concat(center).Concat(last).ToArray(); }
Ich bin dann auf den Datentyp 'dynamic' gestossen und habe meine Funktion wie folgt umgeschrieben:
public static dynamic[] ConvolutionOn1DimArr(dynamic[] arr, dynamic[] filter, int? centerIndex = null, dynamic borderValue = null) { if (arr == null || filter == null) return arr; if (centerIndex == null) centerIndex = filter.Length / 2; if (centerIndex < 0 || centerIndex >= filter.Length) throw new IndexOutOfRangeException("Das Zentrum des Filters liegt ausserhalb des gültigen Bereichs"); var first = arr.Take(centerIndex.Value).Select(v => borderValue == null ? v : borderValue.Value); var last = arr.Skip(arr.Length - filter.Length + centerIndex.Value + 1).Select(v => borderValue == null ? v : borderValue.Value); var center = arr.Skip(first.Count()).Take(arr.Length - first.Count() - last.Count()).Select((v, i) => { var sum = (dynamic)0; for (int n = 0; n < filter.Length; n++) sum += arr[i + n] * filter[n]; return sum; }); return first.Concat(center).Concat(last).ToArray(); }
Leider gibt es dann beim Übersetzen die Fehlermeldung, dass 'int[]' nicht in 'dynamic[]' konvertiert werden kann:
var arr = new int[10];
var filter = new int[3];
ConvolutionOn1DimArr(arr, filter);
Hat jemand eine Idee, wie ich aus der Nummer wieder rauskomme, ohne für jeden Datentyp (int, float, double) eine eigene Implementierung schreiben zu müssen?
Gruß,
Karsten
Antworten
-
Hallo Karsten,
das grundsätzliche Problem liegt darin, dass es keine Operatoren für Generics gibt,
siehe dazu Jon Skeet / Marc Gravell: http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.htmlDies könnte ein besserer Ansatz sein, anstatt dynamic zu verwenden, womit der Code insgesamt als late binding arbeitet.
Da Du keine Testdaten mitgeliefert hast und ich auf die schnelle keine produzieren konnte (wollte),
wäre eine mögliche Zwischenlösung, dynamic nur dort einzusetzen, wo es notwendig ist.
Das wäre hier die Berechnung für center:var center = arr.Skip(first.Count()).Take(arr.Length - first.Count() - last.Count()).Select((v, i) => { // ab hier dynamic ... dynamic sum = default(T); for (int n = 0; n < filter.Length; n++) sum += (dynamic)arr[i + n] * filter[n]; return (T)sum; // ... Ende dynamic });
wobei das Ganze (ungetestet und somit) ohne Gewähr ist.
Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 27. April 2012 07:23
Alle Antworten
-
Hallo Karsten,
das grundsätzliche Problem liegt darin, dass es keine Operatoren für Generics gibt,
siehe dazu Jon Skeet / Marc Gravell: http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.htmlDies könnte ein besserer Ansatz sein, anstatt dynamic zu verwenden, womit der Code insgesamt als late binding arbeitet.
Da Du keine Testdaten mitgeliefert hast und ich auf die schnelle keine produzieren konnte (wollte),
wäre eine mögliche Zwischenlösung, dynamic nur dort einzusetzen, wo es notwendig ist.
Das wäre hier die Berechnung für center:var center = arr.Skip(first.Count()).Take(arr.Length - first.Count() - last.Count()).Select((v, i) => { // ab hier dynamic ... dynamic sum = default(T); for (int n = 0; n < filter.Length; n++) sum += (dynamic)arr[i + n] * filter[n]; return (T)sum; // ... Ende dynamic });
wobei das Ganze (ungetestet und somit) ohne Gewähr ist.
Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 27. April 2012 07:23
-
Für die "kritische" Zeile könntest Du auch ein Delegate hineinreichen, dass die Berechnung übernimmt:
Dynamic is oft ein bisschen slow.
public static T[] ConvolutionOn1DimArr<T>(Func<T, T[], T[], T> mathDelegate, T[] arr, T[] filter, int? centerIndex = null, T? borderValue = null) where T : struct { //... T sum = default(T); for (int n = 0; n < filter.Length; n++) sum = mathDelegate.Invoke(sum, arr[i + n], filter[n]); //... } /* Aufruf: */ var arr = new int[10]; var filter = new int[3]; Func<int, int[], int[], int> mathDelegate = (sum, f1, f2) => sum + (f1 * f2); ConvolutionOn1DimArr(mathDelegate, arr, filter); //oder var arr = new double[10]; var filter = new double[3]; Func<double, double[], double[], double> mathDelegate = (sum, f1, f2) => sum + (f1 * f2); ConvolutionOn1DimArr(mathDelegate, arr, filter);
Gruß,
Christoph
- Bearbeitet Chris-von-der-Wiese Mittwoch, 11. April 2012 14:22