Extensions und mehr.

    • VB.NET
    • .NET (FX) 4.0

    Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

      Extensions und mehr.

      (Vorraussetzung dieses Tuts ist Kenntnis und richtiges Verständnis der Fachbegriffe, wie Modul, Methode, Klasse, Interface, Datentyp, etc.)
      Extensions sind einfach Methoden in einem Modul - etwa hier eine Methode LastRightCut():

      VB.NET-Quellcode

      1. Imports System.Runtime.CompilerServices
      2. Public Module StringX
      3. ''' <returns>den Stringabschnitt ab dem letzten Auftreten von sMatch (ohne sMatch)</returns>
      4. Public Function LastRightCut(s As String, sMatch As String) As String
      5. Dim i = s.LastIndexOf(sMatch)
      6. If i < 0 Then Return Nothing
      7. Return s.Substring(i + sMatch.Length)
      8. End Function
      9. End Module
      Damit kann man zB den Datei-Typ eines Dateipfades ermitteln:

      VB.NET-Quellcode

      1. Dim ext = LastRightCut("C:\kjkee\blabla.txt", ".") ' ergibt: 'txt'


      Eine Extension-Methode wird das einfach durch hinzufügen des Extension-Attributs:

      VB.NET-Quellcode

      1. ''' <returns>den Stringabschnitt ab dem letzten Auftreten von sMatch (ohne sMatch)</returns>
      2. <Extension()> _
      3. Public Function LastRightCut(s As String, sMatch As String) As String
      4. '...

      Nun kann mans wie eine ObjektMethode der String-Klasse aufrufen:

      VB.NET-Quellcode

      1. Dim ext = "C:\kjkee\blabla.txt".LastRightCut(".") ' ergibt: 'txt'
      was viel einfacher zu lesen und (dank Intellisense) zu schreiben ist.
      Das ist im Grunde auch schon alles: Extensions sind ganz normale Methoden, nur tun sie als ob sie Objekt-Methoden wären.
      Das erste Argument wird quasi "rausgezogen", und als Objekt vor die Methode gestellt, und dann siehts genauso aus wie eine Objekt-Methode - des ersten Arguments.
      Und deshalb sinds eben Extensions - man kann nun (Pseudo-)Objekt-Methoden schreiben - aber ohne die Klasse zu verändern! 8|

      Nun kann man mit Extensions aber Datentypen ganz allgemein erweitern - nicht nur Klassen.
      Auch Interfaces (sind ja auch Datentypen) kann man erweitern. Zum Beispiel durch exzessive Erweiterungen des IEnumerable(Of T) - Interfaces schafft Linq (Language Integrated Query) eine eigene (Abfrage-)Sprache innerhalb der Sprache.

      Vergleichbares kann man auch selber machen - nehmen wir mal das Interface IComparable, das ist folgendermaßen definiert (bitte überzeugt euch selbst davon - im ObjectBrowser):

      VB.NET-Quellcode

      1. Public Interface IComparable
      2. Function CompareTo(other As Object) As Integer
      3. End Interface
      Diese Interface definiert: eine Klasse, die comparable sein will, muss eine Methode CompareTo(other) aufweisen, mit der ein Objekt dieser Klasse sich mit einem anderen vergleicht. Zurückgegeben wird ein Integer, der 3 Bedeutungen haben kann:
      • < 0 : Ich bin kleiner als der andere
      • = 0 : Ich bin gleich-groß
      • > 0 : Ich bin größer als der andere
      Dieses Interface implementieren viele wichtige Datentypen: String, Char, DateTime, TimeSpan und natürlich alle Zahl-Typen - ohne das könnte man zB überhaupt nicht sortieren.
      Nun tritt es recht häufig auf, dass man ermitteln muss, ob ein Wert innerhalb eines bestimmten Bereiches liegt.
      Da muss man jedesmal zwei Vergleiche verknüpfen:

      VB.NET-Quellcode

      1. If numb >= 9 AndAlso numb <= 25 Then...
      2. 'oder (umständlicheres Beispiel)
      3. If "HalifaxBlaBla" >= "A" Andalso "HalifaxBlaBla" <= "F" Then...
      Also wem das zu blöd ist, der kann sich ja eine Extension-Methode schreiben:

      VB.NET-Quellcode

      1. Imports System.Runtime.CompilerServices
      2. Public Module IComparableX
      3. <Extension()> _
      4. Public Function IsBetween(Of T As IComparable)(toTest As T, lBound As T, uBound As T) As Boolean
      5. Return lBound.CompareTo(toTest) <= 0 AndAlso toTest.CompareTo(uBound) <= 0
      6. End Function
      7. '...
      Nun kann er so machen:

      VB.NET-Quellcode

      1. If numb.IsBetween(9, 25) Then...
      2. 'oder
      3. If "HalifaxBlaBla".IsBetween("A", "F") Then...
      Kurz: Mit Extensions kann man alles mögliche, was einem an irgendwelchen Datentyp-Features im Framework fehlen mag, selbst hinzu-programmieren :D

      Generische Programmierung
      Habt ihr sicher bemerkt: So nebenbei sind wir mit dem letzten Beispiel in die generische Programmierung eingestiegen. Nämlich meine IsBetween() - Methode hat einen Typ-Parameter T. Das bedeutet, die Methode weiß gar nicht, was für ein Datentyp ihr übergeben wird - es kann jeder mögliche sein. Und das AufrufeBeispiel zeigt ja auch: Es funktioniert mit Integer so gut wie mit String.
      Das einzige, was die Methode über ihr T weiß ist, dass es IComparable implementiert, und also die fabelhafte .CompareTo() - Methode haben muss.
      Dass IsBetween() das weiß liegt an der Typ-Einschränkung, formuliert durch As IComparable innerhalb des TypParameters der Methode (bitte nochmal gucken: zeile#4).
      Und dank dieser Typ-Einschränkung verhält sich Intellisense nun auch intellisent: IsBetween() wird mir nur bei comparablen Datentypen angeboten, bei anderen (wie etwa Button oder FileInfo) nicht:
      <-- draufklicksen, damit es vergrößert wird!

      Also ich empfehle sehr herzlich, das mitte TypEinschränkung und Kram selbst zu recherchieren, etwa - wie in VisualStudio nutzen gezeigt - indem man den Cursor auf das As setzt, und dann F1 drückt. Vlt. kommt ihr ja auch erstmal hier raus, und weiterführend dann hier.

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Beispiele aus meiner Bastelwerkstatt

      Generell nerven mich statische Methoden. ZB ist mir noch nicht ganz klar, warum ein Array sich nicht selbst sortieren kann. Stattdessen muss man umständlich das statische Array.Sort() aufrufen:

      VB.NET-Quellcode

      1. Dim numbs = {5,3,6,9,1,0,2,5,6}
      2. Array.Sort(numbs)
      3. 'Warum geht nicht:
      4. numbs.Sort()
      Naja - es geht ja, wenn man sich eine Extension dafür bastelt:

      VB.NET-Quellcode

      1. Imports System.Runtime.CompilerServices
      2. Public Module CollectionX
      3. <Extension(), DebuggerStepThrough()> _
      4. Public Sub Sort(Of T)(items() As T)
      5. Array.Sort(items)
      6. End Sub
      Jetzt gehts :D

      Dasselbe gilt für Array.Copy(), .Contains(), .IndexOf(), .Find(), .FindIndex(), .ConvertAll()

      VB.NET-Quellcode

      1. ''' <summary> erstellt ein neues Array, und kopiert den angegebenen Bereich hinein </summary>
      2. <Extension()> _
      3. Public Function Take(Of T)(items As T(), start As Integer, count As Integer) As T()
      4. ReDim Take(count - 1)
      5. Array.Copy(items, start, Take, 0, count)
      6. End Function
      7. <Extension(), DebuggerStepThrough()> _
      8. Public Function FindIndex(Of T)(Arr() As T, IsMatch As Predicate(Of T)) As Integer
      9. Return Array.FindIndex(Arr, IsMatch)
      10. End Function
      11. <Extension(), DebuggerStepThrough()> _
      12. Public Function Find(Of T)(Arr() As T, IsMatch As Predicate(Of T)) As T
      13. Return Array.Find(Arr, IsMatch)
      14. End Function
      15. <Extension(), DebuggerStepThrough()> _
      16. Public Function IndexOf(Of T)(Arr() As T, Element As T) As Integer
      17. Return Array.IndexOf(Arr, Element)
      18. End Function
      19. <Extension(), DebuggerStepThrough()> _
      20. Public Function Contains(Of T)(Arr() As T, Element As T) As Boolean
      21. Return DirectCast(Arr, IList(Of T)).Contains(Element)
      22. End Function
      23. <Extension(), DebuggerStepThrough()> _
      24. Public Function ToArray(Of TSrc, TDest)(Arr() As TSrc, Converter As Converter(Of TSrc, TDest)) As TDest()
      25. Return Array.ConvertAll(Arr, Converter)
      26. End Function
      Man mag sich wundern, wo das Array.Copy() ist, und das .ConvertAll(). Deren Funktionalität stelle ich anders dar, nämlich statt Array.Copy(arrSrc, start, arrDest, count) gibts bei mir .Take(start, count), und das tickt auch noch bischen anders, denn es erstellt auch noch das Ziel-Array, wo's reinkopiert.
      Und Array.ConvertAll() ist bei mir dargestellt durch .ToArray() - was ein bischen bescheuert klingt, aber im Zusammenhang mit meiner allgemeingültigeren IEnumerable(Of T)-Extensions von mir gesehen werden muss:

      VB.NET-Quellcode

      1. <Extension()> _
      2. Public Function Take(Of T)(items As IEnumerable(Of T), start As Integer, count As Integer) As IEnumerable(Of T)
      3. Return items.Skip(start).Take(count)
      4. End Function
      5. <Extension()> _
      6. Public Function ToArray(Of T, T2)(items As IEnumerable(Of T), selector As Func(Of T, T2)) As T2()
      7. Return items.Select(selector).ToArray
      8. End Function
      Mein .Take() nimmt ab dem start-Index count Elemente, und mein .ToArray() wandelt eine Auflistung des einen Typs um in ein Array eines anderen Typs. Und weil ich das schon hab, scheints mir sinnvoll, dieselbe Funktionalität auch unter demselben Namen bereitzustellen - aber auf Arrays optimiert. Und das macht dann die statischen Methoden Array.Copy() zu 95% und Array.ConvertAll() zu 100% überflüssig.

      Hier noch AufrufeBeispiele:

      VB.NET-Quellcode

      1. Dim sNumbs = "5 3 6 44 9 1 0 2 5 6".Split
      2. sNumbs.Sort() 'ergibt {"0", "1", "2", "3", "44", "5", "5", "6", "6", "9"}
      3. Dim sNumbs2 = sNumbs.Take(4, 3) ' ergibt {"44", "5", "5"}
      4. Dim bool = sNumbs.Contains("7") ' ergibt False
      5. Dim i = sNumbs.IndexOf("7") ' ergibt -1
      6. Dim str = sNumbs.Find(Function(s) s.Length = 2) ' findet "44"
      7. Dim numbs As Integer() = sNumbs.ToArray(AddressOf Integer.Parse) ' ergibt {0, 1, 2, 3, 44, 5, 5, 6, 6, 9}
      8. numbs = sNumbs.ToArray(Function(s) Integer.Parse(s) * 2) ' ergibt {0, 2, 4, 6, 88, 10, 10, 12, 12, 18}
      9. numbs = numbs.Take(4, 3) ' ergibt {88, 10, 10}
      Damit wären wir bei den nächsten advanced Sprach-Features angekommen:

      bei Delegaten und anonymen Methoden.
      Zeile#7 übergibt einen Funktions-Zeiger als Argument: AddressOf Integer.Parse. Funktions-Zeiger können nur an Delegaten zugewiesen werden, und der Delegat hier ist halt das Methoden-Argument vom Typ - nochmal gucken - Converter(Of TSrc, TDest).
      Also eine Function, die den einen Typ: TSrc als Argument erwartet, und den anderen Typ: TDest dafür zurückgibt.
      Und Integer.Parse() ist ja genau so eine Funktion: Erwartet einen String, gibt einen Integer zurück.
      Also diesen Delegaten übergibt man meiner .ToArray() - Methode, und die macht dann aus dem String-Array sNumbs das Integer-Array numbs.
      Jo - dank des Delegaten-Konzepts ist auch das Konzept "anonyme Methode" möglich
      Das sind Methoden ohne Addresse. Eine normale Methode liegt ja in einer Klasse oder einem Modul, und daraus ergibt sich ihre Addresse, die per AddressOf an einen Delegaten zugewiesen werden kann.
      Eine anonyme Methode nun hat keine Addresse, und liegt nirgendwo, sondern fliegt irgendwo im Speicher herum, und einzig ein Delegat zeigt auf sie.
      Um eine anonyme Methode zu notieren werden die Schlüsselworte Sub, Function bisserl abweichend verwendet - ihr seht ja Beispiel: Function(s) Integer.Parse(s) * 2 Das ist eine Funktion, die einen String entgegennimmt, ihn in einen Integer parst, den verdoppelt und zurückgibt.
      Für so Kleinkram ists halt übersichtlicher, wenn man das gleich da notieren kann, wos zum Einsatz kommt - eine richtige Methode müsste man erst schreiben und dann mit AddressOf zuweisen - wäre etwas unübersichtlicher (und viele kleine Unübersichtlichkeiten sind auch ein Tohuwabohu).

      Noch mehr aus meiner Bastelwerkstatt
      Meine String-Extensions sind glaub am einfachsten zu verstehen, denn das sind stinknormale Methoden, nur - wie ganz eingangs erwähnt - als Extension attributiert und feddich:
      StringX

      VB.NET-Quellcode

      1. Imports System.Runtime.CompilerServices
      2. Public Module StringX
      3. ''' <summary>gibt den String-Abschnitt links des ersten gefundenen Matches zurück</summary>
      4. <Extension()> _
      5. Public Function LastLeftCut(Subj As String, Pattern As String) As String
      6. Dim i = Subj.LastIndexOf(Pattern)
      7. Return If(i >= 0, Subj.Remove(i), Nothing)
      8. End Function
      9. ''' <summary> gibt den String-Abschnitt links des ersten gefundenen Matches zurück </summary>
      10. <Extension()> _
      11. Public Function LeftCut(Subj As String, Pattern As String) As String
      12. Dim i = Subj.IndexOf(Pattern)
      13. Return If(i >= 0, Subj.Remove(i), Nothing)
      14. End Function
      15. ''' <returns>den Stringabschnitt ab dem letzten Auftreten von sMatch (ohne sMatch)</returns>
      16. <Extension()> _
      17. Public Function LastRightCut(s As String, sMatch As String) As String
      18. Dim i = s.LastIndexOf(sMatch)
      19. If i < 0 Then Return Nothing
      20. Return s.Substring(i + sMatch.Length)
      21. End Function
      22. ''' <returns>den Stringabschnitt ab dem ersten Auftreten von sMatch (ohne sMatch)</returns>
      23. <Extension()> _
      24. Public Function RightCut(S$, sMatch$) As String
      25. Dim I% = S.IndexOf(sMatch)
      26. If I < 0 Then Return Nothing
      27. Return S.Substring(I + sMatch.Length)
      28. End Function
      29. '''<summary> verkettet alles</summary>
      30. <Extension()> _
      31. Public Function [And](Subj As String, ParamArray others() As Object) As String
      32. Return String.Concat(Subj, String.Concat(others))
      33. End Function
      34. Public Enum Additional : None : Start : [End] : Start_End : End Enum
      35. <Extension()> _
      36. Public Function Between(separator As Char, additional As Additional, ParamArray args() As Object) As String
      37. Return Between(args, separator, additional)
      38. End Function
      39. <Extension()> _
      40. Public Function Between(separator As Char, ParamArray args() As Object) As String
      41. Return Between(args, separator, Additional.None)
      42. End Function
      43. <Extension()> _
      44. Public Function Between(separator As String, additional As Additional, ParamArray args() As Object) As String
      45. Return Between(args, separator, additional)
      46. End Function
      47. <Extension()> _
      48. Public Function Between(separator As String, ParamArray args() As Object) As String
      49. Return Between(args, separator, Additional.None)
      50. End Function
      51. Private _SB As New System.Text.StringBuilder
      52. <DebuggerStepThrough()> _
      53. Private Function Between(args() As Object, separator As String, additional As Additional) As String
      54. Try
      55. While args.Length < 2
      56. args = DirectCast(args(0), IEnumerable).Cast(Of Object).ToArray
      57. End While
      58. Catch ex As Exception ' can be InvalidCast or IndexOutOfRange
      59. Throw New ArgumentException("Between() - args must have minimum 2 elements", "args")
      60. End Try
      61. _SB.Clear()
      62. If additional.HasFlag(additional.Start) Then _SB.Append(separator)
      63. _SB.Append(String.Join(separator, args))
      64. If additional.HasFlag(additional.End) Then _SB.Append(separator)
      65. Return _SB.ToString
      66. End Function
      67. End Module

      Die Abschneide-Funktionen hab ich im Prinzip ja schon in post#1 erklärt, bleiben noch .And() und .Between().
      .And() ist meine Verbesserung der statischen String.Concat() - Methode. Wie beim Original kann man beliebig alles hineinschmeissen Beispiel:

      VB.NET-Quellcode

      1. 'statt
      2. str = String.Concat("sNumbs2 ist vom Datentyp ", sNumbs2.GetType.Name, ", hat ", sNumbs2.Length, " Elemente, das kleinste ist:", sNumbs2(0))
      3. 'oder gar
      4. str = "sNumbs2 ist vom Datentyp " & sNumbs2.GetType.Name & ", hat " & sNumbs2.Length & " Elemente, das kleinste ist:" & sNumbs2(0)
      5. 'heisstes bei mir:
      6. str = "sNumbs2 ist vom Datentyp ".And(sNumbs2.GetType.Name, ", hat ", sNumbs2.Length, " Elemente, das kleinste ist:", sNumbs2(0))

      .Between() ist meine String.Join() - Verbesserung:

      VB.NET-Quellcode

      1. 'statt
      2. str = String.Join("-", numbs) ' ergibt "88-10-10"
      3. 'heisstes bei mir:
      4. str = "-".Between(numbs) ' ergibt "88-10-10"
      5. 'mit Separator vorangestellt:
      6. str = "-".Between(Additional.Start, numbs) ' ergibt "-88-10-10"
      7. str = "-".Between(numbs).Between("<>") ' ergibt "<88-10-10>"


      Besondere Extension-Tricks
      Da Extensions nur so tun als ob sie Objekt-Methoden wären, geht auch sowas:

      VB.NET-Quellcode

      1. Public Module ObjectX
      2. <DebuggerStepThrough(),Extension()> _
      3. Public Function Null(Of T As Class)(Subj As T) As Boolean
      4. Return Subj Is Nothing
      5. End Function
      6. <DebuggerStepThrough(), Extension()> _
      7. Public Function NotNull(Of T As Class)(Subj As T) As Boolean
      8. Return Subj IsNot Nothing
      9. End Function
      Mit echten Objekt-Methoden paradox-undenkbar, dass ein Objekt von sich selbst wissen kann, dass es Nothing ist. Aber hier erzeugen Sokrates und Descartes einen wahrhaft unglaublichen philosophischen Synergie-Effekt:
      "Ich weiß, dass ich nicht bin." ;)
      Brauche ich total oft, diesen Test auf Nothing:

      VB.NET-Quellcode

      1. dim str = sNumbs.FirstOrDefault(Function(s)s.Length >2)
      2. if str.Null then Messagebox.Show("sNumbs enthält keinen String länger als 2")

      Eine weiterer Spezial-Effekt tritt auf, wenn man den Extension-Parameter ByRef wählt:

      VB.NET-Quellcode

      1. <Extension()> _
      2. Public Sub Maximize(Of T As IComparable)(ByRef subj As T, other As T)
      3. If other.CompareTo(subj) > 0 Then subj = other
      4. End Sub
      5. ''' <summary>cast value to desired Type and assigns it. Causes InvalidCastException on failure</summary>
      6. <DebuggerStepThrough(), Extension()> _
      7. Public Sub Be(Of T)(ByRef target As T, value As Object)
      8. target = DirectCast(value, T)
      9. End Sub
      Aufruf:

      VB.NET-Quellcode

      1. Dim X = 12
      2. 'statt
      3. X = Math.Max(X, 99)
      4. 'einfach
      5. X.Maximize(99)
      6. Dim bt As Button
      7. 'statt
      8. bt = DirectCast(Controls(0), Button)
      9. 'einfach
      10. bt.Be(Controls(0))


      Und noch ein'

      VB.NET-Quellcode

      1. <Extension()> _
      2. Public Sub ForEach(Of T)(items As IEnumerable, Action As Action(Of T))
      3. For Each itm As T In items
      4. Action(itm)
      5. Next
      6. End Sub
      Damit kann man kleine Foreach-Schleifen als Einzeiler formulieren

      VB.NET-Quellcode

      1. Dim buttons = {Button1, Button2, Button3}
      2. 'statt
      3. For Each bt In buttons
      4. SplitContainer1.Panel1.Controls.Add(bt)
      5. Next
      6. 'einfach
      7. buttons.ForEach(AddressOf SplitContainer1.Panel1.Controls.Add)

      Und noch ein'

      VB.NET-Quellcode

      1. <Extension(), DebuggerStepThrough()> _
      2. Public Sub Swap(items As IList, I1 As Integer, I2 As Integer)
      3. Dim Tmp = items(I1)
      4. items(I1) = items(I2)
      5. items(I2) = Tmp
      6. End Sub
      Das vertauscht Items in beliebigen indizierbaren Auflistungen, etwa Button1 und Button3 würden so die Plätze tauschen:

      VB.NET-Quellcode

      1. buttons.Swap(0,2)

      Faszit
      (Einfachere) Extensions sind oft weniger ein Must-Have denn ein Nice-To-Have (oder Very-Nice-To-Have): Ohne das kommt man auch durch, nur bischen umständlicher.
      Komplexere Extensions können aber auch merklich mehr leisten als nur 2 Zeilen vlt. auf eine zu reduzieren, zB. Extensions für Listen oder verbesserte AggregatFunktion für Linq-Max / Linq-Min

      Äusserst bedeutsam ist der Synergie-Effekt zwischen den 4 Sprach-Features: Extensions, Generica, Delegaten und anonymen Methoden: Das gesamte Linq - System ist auf dem eng verzahnten Zusammenwirken aller 4 SprachFeatures aufgebaut, und anders nicht denkbar.

      Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „ErfinderDesRades“ ()

      String.FormatX() - Extension

      Neulich habich einen Code-Generator gebastelt, und da habe ich exzessiv die String.Format-Methode bemüht.
      Die ich normalerweise vermeide, weil ich verhaspel mich immer mit der Numerierung im Format-String.

      Nun, meine String.FormatX-Extension() ermöglicht, bei einfachem Einfügen von Argumenten, dass man im Format-String die Nummer weglassen kann - er fügt die Argumente dann einfach der Reihe nach ein.
      Und wenn mehr Platzhalter im FormatString auftreten, als einzufügende Argumente mitgegeben sind, so benutzt er das letzte Argument einfach mehrmals - so oft wie angefragt.
      Eine komplette Methode zu generieren ging dann in eine Zeile:

      VB.NET-Quellcode

      1. Write("Public Sub New(dts As {}){} Me.New(){}Dataset = dts{}End Sub", _DtsName, Lf)
      (Hier wars besonders günstig, denn das erste Argument ist der Dataset-Name, und alle weiteren Platzhalter markierten Zeil-Umbrüche.)
      Mit Standard-Formatierung wärs auch gegangen, nur bisserl umständlicher:

      VB.NET-Quellcode

      1. myStreamWriter.WriteLine(String.Format("Public Sub New(dts As {0}){1}Me.New(){1}Dataset = dts{1}End Sub", _DtsName, Lf))
      Jedenfalls die FormatX-Extension verhält sich genau wie die String.Format-Funktion, erweitert diese nur um Platzhalter-Syntax, bei der die Numerierung weggelassen werden darf.

      Ausserdem hänge ich jetzt mal eine Sample-Solution an, bestehend aus dem eigentlichen Tester-Projekt, und dem Helpers-Projekt, wo die hier im Thread vorgestellten Extensions drinne sind. Ist vlt. auch ganz nützlich, auch den Aufbau einer Solution mal zu sehen, wo das Main-Project ein Helpers-Projekt mit den Extensions einbindet.
      (näheres dazu auch unter Video: HelperProjekt einbinden)

      Credits an @nafets, für den Regex, der Anwendung findet :)
      Dateien
      Wie bildet denn deine Extension folgende nützliche Funktionalität von String.Format ab?
      String.Format("{0} ist ein User in {1}, sein Nickname ist {0}", "ErfinderDesRades", "VbParadise")

      Damit gibt man ein Element, das man mehrmals einfügen will, nur einmal an und erkennt im Formatstring, dass an diesen Stellen das Selbe steht.
      etwa so:

      VB.NET-Quellcode

      1. MessageBox.Show("{0} ist ein User in {1}, sein Nickname ist {0}".FormatX("ErfinderDesRades", "VbParadise"))
      Also da kann man die Numerierung nicht weglassen, weil das 1. Argument wird auch für den 3. Platzhalter gebraucht.
      Somit ist der einzige Benefit, dass FormatX() sich als Objekt-Methode gebärdet (einschließlich Intellisense) statt als Statische Methode.

      Möglich wäre allerdings sowas:

      VB.NET-Quellcode

      1. MessageBox.Show("{} ist ein User in {}, sein Nickname ist {0}".FormatX("ErfinderDesRades", "VbParadise"))
      Aber das ist auch bischen durchtrieben, und eiglich nicht einfacher.

      Vereinfachung erhielte man bei einer anderen Ausgabe, etwa

      VB.NET-Quellcode

      1. MessageBox.Show("{} ist ein User in {}, wem das zu lang ist, der notiert '{}'".FormatX("ErfinderDesRades", "VbParadise", "Edr"))

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()