PDA

View Full Version : آموزش: Extension Methods



ROSTAM2
چهارشنبه 13 مهر 1401, 23:01 عصر
سلام.

با استفاده از Extension Method شما می تونید برای هر کلاسی که می خواهید متود Sub, Function اضافه کنید و از اون متودها توی ماجول هاتون استفاده کنید.

ابتدا یک ماجول به پروژه تون اضافه می کنید نامش رو نام کلاسی میگذارید که می خواهید براش Extension بسازید و در ادامه کلمه Extensions رو تایپ می کنید:



Module StringExtensions

End Module



و قبل از هر چیز باید این فضای نام رو به ماجول اضافه کنید:



Imports System.Runtime.CompilerServices



حالا هر متودی که می خواهید به کلاس مدنظر اضافه کنید ایجاد می کنید با این ویژگی که باید پارامتر یا ورودی اول نوع دیتاش همون کلاسی باشه که می خواهید Extensions رو به اون اضافه کنید:



Imports System.Runtime.CompilerServices


Module StringExtensions


<Extension()>
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub


End Module



به هر متود در این ماجول باید یک اتریبوت Extension اختصاص داده بشه.

بکارگیری Extension Method:


Module Module1


Sub Main()
Dim example As String = "Example string"
example.Print()

End Sub
End Module



مرجع: https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods

ROSTAM2
یک شنبه 17 مهر 1401, 21:16 عصر
سلام به همه.

دو Extension Method برای متغیر های رشته ای: حذف کاراکتر از انتهای رشته به تعداد ورودی len


Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()> Function RemoveEnd(Str As String, Optional len As Integer = 1) As String
If Str.Length = 0 Then Return ""
Return Str.Remove(Str.Length - len, len)
End Function
<Extension()> Sub RemovingEnd(ByRef Str As String, Optional len As Integer = 1)
If Str.Length > 0 Then
Str = Str.Remove(Str.Length - len, len)
End If
End Sub
End Module

ROSTAM2
دوشنبه 18 مهر 1401, 20:20 عصر
سلام.

دوتا Extension Method برای متغیر های رشته ای : به ابتدا یا انتهای رشته می شه متن اضافه کرد و برای جداسازی هر متن اضافه شده می شه بهش delimiter یا کاراکتر جداکننده ضمیمه کرد.


<Extension()> Sub AppendAfter(ByRef str As String, value As String, Optional delimiter As String = "")
Dim Expr As String = If(str.Length > 0, delimiter, "")
str = str.Insert(str.Length, Expr + value)
End Sub
<Extension()> Sub AppendBefor(ByRef str As String, value As String, Optional delimiter As String = "")
Dim Expr As String = If(str.Length > 0, delimiter, "")
str = str.Insert(0, value + Expr)
End Sub

ROSTAM2
جمعه 22 مهر 1401, 18:22 عصر
یک Extension Method برای String -

تابعی برای بدست آوردن تعداد فاصله های موجود در انتهای یک متن:

<Extension()> Function EndSpaces(str As String) As Integer
If str.Length = 0 Then Return 0
Dim SPL() As String = str.Split(Space(1))
Dim Spaces As Int16 = 0
If str.Length > 0 Then
For i = SPL.Length - 1 To 0 Step -1
If SPL(i).Length = 0 Then
Spaces += 1
Else
Exit For
End If
Next
End If
Return Spaces
End Function


اگه روش بهتری برای بدست آوردن فاصله های انتهایی موجود در متن دارید توی همین تاپیک مطرح کنید.

ROSTAM2
جمعه 22 مهر 1401, 18:24 عصر
یک Extension Method برای String

این تابع آخرین خط از یک متن رو بر می گردونه:

<Extension()> Function LastLine(str As String) As String
Dim Lines() As String = str.Split(Chr(10), Chr(13))
If Lines.Length = 0 Then Return ""
If Lines.Length > 0 Then
Return Lines(Lines.Length - 1)
End If
Return ""
End Function


اگه روش بهتری دارید در همین تاپیک مطرح کنید.

ROSTAM2
جمعه 22 مهر 1401, 18:28 عصر
یک Extension Method برای String

این تابع کلمه ای رو که در رشته ویرایش کردید رو بر می گردونه: و با وجود دو ورودی قابل ارجاع sIndex و eIndex به برنامه نویس این امکان رو می ده تا بتونه خارج از متد شماره Index شروع و پایان کلمه در متن رو بدست بیاره.


''' <summary>
''' Get Current Changed Word
''' </summary>
''' <param name="str"></param>
''' <param name="Position">Start Position to check(e.x. Console.CursorLeft)</param>
''' <param name="sIndex">Referenced Start Index</param>
''' <param name="eIndex">Referenced End Index</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()> Function CurrentWord(str As String, Position As Integer, Optional ByRef sIndex% = 0, Optional ByRef eIndex% = 0) As String
Dim StartIndex As Integer, EndIndex As Integer
If str.Substring(Position).Length = 0 Then Return ""
str = str.TrimEnd
'Debug.Print("CurrentWord Position: {0}", Position)
For i = Position To 0 Step -1
If str(i).CompareTo(" "c) = 0 Then
StartIndex = i
GoTo EndIndex
End If
Next
StartIndex = 0
EndIndex: 'Debug.Print("StartIndex: {0}", StartIndex)
For i = Position To str.Length - 1 Step 1
If str(i).CompareTo(" "c) = 0 Then
EndIndex = i
GoTo ReturnValue
End If
Next
EndIndex = str.Length - 1
ReturnValue: 'Debug.Print("EndIndex: {0}", EndIndex)
sIndex = StartIndex
eIndex = EndIndex
Dim Len% = (EndIndex - StartIndex) + 1
'Debug.Print("Word: {0}", str.Substring(StartIndex, Len))
Return str.Substring(StartIndex, Len)
End Function


اگه روش بهتری دارید یا اگه خطایی داره در همین تاپیک مطرح کنید.

mazoolagh
شنبه 23 مهر 1401, 09:05 صبح
یک Extension Method برای String -

تابعی برای بدست آوردن تعداد فاصله های موجود در انتهای یک متن:

<Extension()> Function EndSpaces(str As String) As Integer
If str.Length = 0 Then Return 0
Dim SPL() As String = str.Split(Space(1))
Dim Spaces As Int16 = 0
If str.Length > 0 Then
For i = SPL.Length - 1 To 0 Step -1
If SPL(i).Length = 0 Then
Spaces += 1
Else
Exit For
End If
Next
End If
Return Spaces
End Function


اگه روش بهتری برای بدست آوردن فاصله های انتهایی موجود در متن دارید توی همین تاپیک مطرح کنید.

سلام و روز خوش
پیش از هر چیز باید برای این آموزش مفید همراه با توضیح کامل تشکر کنم، برای خود من تازگی داشت.

چند مورد به ذهنم رسید:

1- اگر str برابر empty یا null باشه str.length باعث خطا میشه،
بهتر هست که از تابع isnullorempty استفاده بشه.

2- اگر در انتهای str فقط دنبال space باشیم ممکن هست که نتیجه اشتباه بگیریم،
اگر tab یا enter (CR+LF) در انتها باشه این کد تشخیص نمیده.

3- در کل ساده تر هم میشه نوشت:

<Extension()> Function EndSpaces(str As String) As Integer
if string.isnullorempty(str) then
return 0
else
return str.length - str.trimend.length
end if
End Function

البته این کد تشخیص نمیده که str با چی تموم شده (اگر لازم باشه میشه اصلاحش کرد)،
ولی این رو که در پایانش whitespace داره یا نه درست چک میکنه.

ROSTAM2
شنبه 23 مهر 1401, 19:33 عصر
آفرین.
من اصلا توجهی به اون محاسبه با TrimEnd نداشتم. ممنون تابع رو کاملتر کردم و یک Enumeration داریم که مقادیر دلخواه رو می تونیم به ورودی دوم که اختیاری هم هست بدیم تا تعداد Whitespace رو طبق اون ورودی محاسبه کنیم.

تابع تصحیح شده:

<Extension()> Function EndWhitespaces(str As String, Optional Kind As WhitespaseKind = WhitespaseKind.All) As Integer
If str.Length = 0 Then Return 0
Dim Chars() As Char
Dim WhiteSpaceLen As Int16 = str.Length - str.TrimEnd.Length
Dim CompChar As Char = vbNullChar
Dim StartIndex%, Len%
Dim WhiteSpaces% = 0
StartIndex = (str.Length - WhiteSpaceLen)
Len = WhiteSpaceLen
Select Case Kind
Case WhitespaseKind.All
Return WhiteSpaceLen
Case WhitespaseKind.Space
CompChar = Chr(32)
Case WhitespaseKind.vbCr
CompChar = Chr(13)
Case WhitespaseKind.vbCrlf
If Len Mod 2 = 0 Then
For i = StartIndex To str.Length - 1 Step 2
Debug.Print("->", str.Substring(i, 2))
If str.Substring(i, 2).CompareTo(Chr(13) & Chr(10)) = 0 Then
WhiteSpaces += 1
End If
Next
End If
GoTo ReturnLine
Case WhitespaseKind.vbLf
CompChar = Chr(10)
End Select
Chars = str.ToCharArray(StartIndex, Len)
For i = 0 To Chars.Length - 1
If Chars(i).CompareTo(CompChar) = 0 Then
WhiteSpaces += 1
End If
Next
ReturnLine:
Return WhiteSpaces
End Function


و این هم WhitespaceKind Enumeration:

<Flags()> _
Enum WhitespaseKind
All = 0
Space = 2
''' <summary>
''' vbCr Chr(13) Carriage return
''' Represents a carriage-return character for print and display functions.
''' </summary>
''' <remarks>return to line beginning</remarks>
vbCr = 3
''' <summary>
''' vbCrLf Chr(13) + Chr(10) Carriage return–linefeed combination
''' Represents a carriage-return character combined with a linefeed character for print and display functions.
''' </summary>
''' <remarks>similar to pressing Enter</remarks>
vbCrlf = 7
''' <summary>
''' vbLf Chr(10) Line feed
''' Represents a linefeed character for print and display functions.
''' </summary>
''' <remarks>go to next line</remarks>
vbLf = 4
End Enum

ROSTAM2
شنبه 23 مهر 1401, 20:41 عصر
دستور Case vbCrlf در پست قبلی درست عمل نمی کرد که صحیحش این هست:

Case WhitespaseKind.vbCrlf
For i = StartIndex To str.Length - 1 Step 2
If i = str.Length - 1 Then Exit For
'Debug.Print("->", str.Substring(i, 2))
If str.Substring(i, 2).CompareTo(Chr(13) & Chr(10)) = 0 Then
WhiteSpaces += 1
End If
Next
GoTo ReturnLine


که این هم تصحیح کامل تابع پست قبل EndWhiteSpaces Extension Method:

<Extension()> Function EndWhitespaces(str As String, Optional Kind As WhitespaseKind = WhitespaseKind.All) As Integer
If str.Length = 0 Then Return 0
Dim Chars() As Char
Dim WhiteSpaceLen As Int16 = str.Length - str.TrimEnd.Length
Dim CompChar As Char = vbNullChar
Dim StartIndex%, Len%
Dim WhiteSpaces% = 0
StartIndex = (str.Length - WhiteSpaceLen)
Len = WhiteSpaceLen
Select Case Kind
Case WhitespaseKind.All
Return WhiteSpaceLen
Case WhitespaseKind.Space
CompChar = Chr(32)
Case WhitespaseKind.vbCr
CompChar = Chr(13)
Case WhitespaseKind.vbCrlf
For i = StartIndex To str.Length - 1 Step 2
If i = str.Length - 1 Then Exit For
'Debug.Print("->", str.Substring(i, 2))
If str.Substring(i, 2).CompareTo(Chr(13) & Chr(10)) = 0 Then
WhiteSpaces += 1
End If
Next
GoTo ReturnLine
Case WhitespaseKind.vbLf
CompChar = Chr(10)
End Select
Chars = str.ToCharArray(StartIndex, Len)
For i = 0 To Chars.Length - 1
If Chars(i).CompareTo(CompChar) = 0 Then
WhiteSpaces += 1
End If
Next
ReturnLine:
Return WhiteSpaces
End Function

ROSTAM2
شنبه 23 مهر 1401, 20:51 عصر
این متود نمونه دیگه ای از همون متود پست قبل هست که نامش به EndWhiteSpace تغییر کرده و نوع خروجی اون یک Structure با نام WhitespaceString هست که کاربرد بیشتری نسبت به متود قبلی داره:

WhitespaceString Structure:

Structure WhitespaceString
Sub New(Value As String)
Me.ValueValue = Value
End Sub
Private ValueValue As String
Public ReadOnly Property Value() As String
Get
Return ValueValue
End Get
End Property


Public ReadOnly Property Length(Optional kind As WhitespaseKind = WhitespaseKind.All) As Integer
Get
Dim Chars() As Char
Dim CompChar As Char = vbNullChar
Dim StartIndex%, Len%
Dim WhiteSpaces% = 0
Len = Value.Length
Select Case kind
Case WhitespaseKind.All
Return Len
Case WhitespaseKind.Space
CompChar = Chr(32)
Case WhitespaseKind.vbCr
CompChar = Chr(13)
Case WhitespaseKind.vbCrlf
For i = 0 To Len - 1 Step 2
If i = Len - 1 Then Exit For
'Debug.Print("->", Value.Substring(i, 2))
If Value.Substring(i, 2).CompareTo(Chr(13) & Chr(10)) = 0 Then
WhiteSpaces += 1
End If
Next
GoTo ReturnLine
Case WhitespaseKind.vbLf
CompChar = Chr(10)
End Select
Chars = Value.ToCharArray(StartIndex, Len)
For i = 0 To Chars.Length - 1
If Chars(i).CompareTo(CompChar) = 0 Then
WhiteSpaces += 1
End If
Next
ReturnLine:
Return WhiteSpaces
End Get
End Property

Public Function Contains(chr As String) As Boolean
Return Value.Contains(chr)
End Function
End Structure


EndWhitespace Extension Method:

<Extension()> Function EndWhitespace(str As String) As WhitespaceString
If str.Length = 0 Then Return Nothing
Dim WhiteSpaceLen As Int16 = str.Length - str.TrimEnd.Length
Dim StartIndex%, Len%
StartIndex = (str.Length - WhiteSpaceLen)
Len = WhiteSpaceLen
Return New WhitespaceString(str.Substring(StartIndex, Len))
End Function


WhitespaceKind Enumeration هم که در پست شماره 8 هست و اینجا برای خصوصیت Length از WhitespaceString Structure بکار گرفته می شه.

ROSTAM2
شنبه 23 مهر 1401, 21:02 عصر
آیا در انتهای متن یک خط جدید NewLine وجود دارد؟
1.

strings.EndWhitespace.Contains(vbNewLine)


2.

strings.EndWhitespace.Contains(vbCrLf)


تعداد کاراکترهای فاصله در انتهای متن چقدر است:

strings.EndWhitespace.Length


تعداد کاراکترهای فاصله مورد سوال بین vbCr, vbCrLf, vbLf, Space


strings.EndWhitespace.Length(WhitespaseKind.Space)

strings.EndWhitespace.Length(WhitespaseKind.vbCr)

strings.EndWhitespace.Length(WhitespaseKind.vbCrlf )

strings.EndWhitespace.Length(WhitespaseKind.vbLf)


برای تشخیص موجود بودن کاراکترهای مورد سوال هم از Contains استفاده می شه:

strings.EndWhitespace.Contains(vbLf)


154085

mazoolagh
پنج شنبه 28 مهر 1401, 14:23 عصر
در ادامه بحث و در مورد متد سودمند پست شماره 10 (https://barnamenevis.org/showthread.php?571605-Extension-Methods&p=2453599&viewfull=1#post2453599) :

در کد زیر از روش دیگه ای استفاده شده که بعضی موارد رو اشاره میکنم:
1- از استراکچر در خود اکستنشن استفاده نشده و نیاز به ساختش به اختیار کاربر واگذار شده. بنابراین مستقیم با خود رشته سروکار داره.
2- روش جستجو کلا متفاوت هست و کد جمع و جورتری داره (به معنی بهتر بودن نیست!)
3- whitespace ها رو هم در ابتدا و هم در انتهای رشته پیدا میکنه.
4- یک متد به اسم formatted داره که blank,tab,cr,lf,crlf رو با کارآکترهای دیدنی جایگزین و به تشخیص موقیعت اونها کمک میکنه.


Const vbBlank As Char = " "
Const zBlank = ChrW(&H25CC) ' ◌
Const zTab = ChrW(&H2192) ' →
Const zCrLf = ChrW(&HB6) ' ¶
Const zLf = ChrW(&H2193) ' ↓
Const zCr = ChrW(&HAC) ' ¬
Const zAny = zBlank + zTab + zCrLf + zLf + zCr


<Extension> Function StartWhiteSpaces(str As String) As String
str = NZ(str)
Return str.Substring(0, str.Length - str.TrimStart.Length)
End Function


<Extension> Function EndWhiteSpaces(str As String) As String
str = NZ(str)
Return str.Substring(str.TrimEnd.Length)
End Function


<Extension> Function Formatted(str As String) As String
Return NZ(str).
Replace(ChrW(32), zBlank).
Replace(vbTab, zTab).
Replace(vbCrLf, zCrLf).
Replace(vbLf, zLf).
Replace(vbCr, zCr)
End Function


<Extension> Function CountOfBlanks(str As String) As Integer
Return NZ(str).Count(Function(chr) chr = vbBlank)
End Function


<Extension> Function CountOfTabs(str As String) As Integer
Return NZ(str).Count(Function(chr) chr = vbTab)
End Function


<Extension> Function CountOfCrs(str As String) As Integer
Return NZ(str).Replace(vbCrLf, String.Empty).Count(Function(chr) chr = vbCr)
End Function


<Extension> Function CountOfLfs(str As String) As Integer
Return NZ(str).Replace(vbCrLf, String.Empty).Count(Function(chr) chr = vbLf)
End Function


<Extension> Function CountOfCrLfs(str As String) As Integer
str = NZ(str)
Return (str.Length - str.Replace(vbCrLf, String.Empty).Length) / 2
End Function


<Extension> Function CountOfWhiteSpaces(str As String) As Integer
Return NZ(str).Formatted.Count(Function(chr) zAny.IndexOf(chr) >= 0)
End Function


<Extension> Function HasBlank(str As String) As Boolean
Return NZ(str).IndexOf(vbBlank) >= 0
End Function


<Extension> Function HasTab(str As String) As Boolean
Return NZ(str).IndexOf(vbTab) >= 0
End Function


<Extension> Function HasCr(str As String) As Boolean
Return NZ(str).Replace(vbCrLf, String.Empty).IndexOf(vbCr) >= 0
End Function


<Extension> Function HasLf(str As String) As Boolean
Return NZ(str).Replace(vbCrLf, String.Empty).IndexOf(vbLf) >= 0
End Function


<Extension> Function HasCrLf(str As String) As Boolean
Return NZ(str).IndexOf(vbCrLf) >= 0
End Function


<Extension> Function HasWhiteSpace(str As String) As Boolean
Return NZ(str).Formatted.IndexOfAny({zBlank, zTab, zCr, zLf, zCrLf}) >= 0
End Function


Private Function NZ(str As String) As String
If String.IsNullOrEmpty(str) Then
Return String.Empty
Else
Return str
End If
End Function

mazoolagh
پنج شنبه 28 مهر 1401, 14:28 عصر
Const Sample As String = vbCr + vbTab + vbLf + vbLf + vbTab + " This is a" + vbTab + vbCrLf + " Test. " + vbTab + vbCrLf


154094