none
programming language

    Question

  • ·         What benefit is there to include a process or a function within my code?

    Wednesday, March 22, 2017 8:51 PM

All replies

  • Hi

    I don't know what you mean by 'include a process', but as for a function, here is an example that may help in showing why they are useful.

    Option Strict On
    Option Explicit On
    Option Infer Off
    Public Class Form1
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            ' pretend that these type of lines are spread
            ' throughout a long piece of project code
            Dim i1 As Integer = GetIntegerFromString("1234")
            Dim i2 As Integer = GetIntegerFromString("1")
            Dim i3 As Integer = GetIntegerFromString("1.1")
            Dim i4 As Integer = GetIntegerFromString(".3434")
            Dim i5 As Integer = GetIntegerFromString("freddy")
            Stop
            ' now imagine having to rewrite the entire function
            ' for every call shown here to the example function
        End Sub
        Function GetIntegerFromString(strg As String) As Integer
            ' pretend that this function is a very long
            ' piece of code
            Dim v As Integer
            If Integer.TryParse(strg, v) Then Return v
            Return 0
        End Function


    Regards Les, Livingston, Scotland


    • Edited by leshay Wednesday, March 22, 2017 9:57 PM
    Wednesday, March 22, 2017 9:56 PM
  • Image you need to check if a date is between two dates or a number is between two numbers? You would need to write and if statement to do the compare, each compare would be against either numbers or dates each time you need to do this check.

    With a function we can write a generic method that checks for us. In this case I will present what is called a language extension that is a function which is called as a method.

    Public Module GenericExtensions
        <Runtime.CompilerServices.Extension>
        Public Function Between(Of T As IComparable(Of T))(ByVal actual As T, ByVal lower As T, ByVal upper As T) As Boolean
            Return actual.CompareTo(lower) >= 0 AndAlso actual.CompareTo(upper) < 0
        End Function
    End Module

    Calling the Between extension

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim someNumber As Integer = 5
        If someNumber.Between(1, 10) Then
            MessageBox.Show($"{someNumber} is between 1 and 10")
        End If
    
        Dim someDate As Date = New DateTime(Now.Year, Now.Month, 1)
        If someDate.Between(#1/1/2017#, Now) Then
            MessageBox.Show($"{someDate.ToShortDateString} is between {#1/1/2017#.ToShortDateString} and {Now.ToShortDateString}")
        End If
    
    End Sub

    Caveat, since the code module is marked as public the code can be placed in the project you want to use it in or even in a separate class project which your project uses as a reference.

    Another example, you want to work with a database. Many novice developers write code directly in a form to access the data in the database. This means if you need to write the same methods in another form (or even in another project) you need to duplicate all or some of the code. Instead using functions in a class we can reuse the exact same code over and over again without duplicating it.

    Example class which in this case is in a class project and used in a Windows forms project. It has methods to read, add, edit and delete.

    Imports System.Data.SqlClient
    Imports System.Windows.Forms
    
    Public Class Operations
        Private ConnectionString As String = "Data Source=KARENS-PC;Initial Catalog=MasterDetailSimple;Integrated Security=True"
        Public Property CustomerTable As DataTable
        Public Property HasErrors As Boolean
        Public Property ExceptionMessage As String
        ''' <summary>
        ''' This is the master data
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Master As New BindingSource
        ''' <summary>
        ''' This is the details to the Master 
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Details As New BindingSource
        ''' <summary>
        ''' This will contain order details for the current order of a customer
        ''' 50FF25
        ''' </summary>
        ''' <returns></returns>
        Public Property OrderDetails As New BindingSource
        Public Property StateInformation As List(Of StateItems)
        Public Sub New()
            GetStateInformation()
        End Sub
        ''' <summary>
        ''' Read state table data into a list
        ''' </summary>
        ''' <remarks>
        ''' First row is virual
        ''' </remarks>
        Private Sub GetStateInformation()
            StateInformation = New List(Of StateItems)
            StateInformation.Add(New StateItems With {.Identifier = -1, .Name = "Select one"})
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = "SELECT id,StateName,StateAbbrev FROM StateLookup"}
                    cn.Open()
                    Dim reader As SqlDataReader = cmd.ExecuteReader
                    While reader.Read
                        StateInformation.Add(New StateItems With {.Identifier = reader.GetInt32(0), .Name = reader.GetString(1), .Abbreviation = reader.GetString(2)})
                    End While
                End Using
            End Using
        End Sub
        ''' <summary>
        ''' Initial data loaded was generated by Red Gate SQL Data Generator
        ''' so the invoice numbers will be different than the ones created
        ''' here with the database sequence I have provided here.
        ''' </summary>
        Public Sub LoadData()
    
            Dim ds As New DataSet
    
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Dim da As New SqlDataAdapter("SELECT id,FirstName,LastName,Address,City,State,ZipCode FROM Customer", cn)
                Try
                    da.Fill(ds, "Customer")
                    Dim dt As DataTable = ds.Tables("Customer")
    
                    da = New SqlDataAdapter("SELECT id,CustomerId,OrderDate,Invoice FROM Orders", cn)
                    da.Fill(ds, "Orders")
                    ds.SetRelation("Customer", "Orders", "Id", "CustomerId")
    
                    da = New SqlDataAdapter("SELECT id,OrderId ,ProductName,UnitPrice,Quantity FROM OrderDetails", cn)
                    da.Fill(ds, "OrderDetails")
                    ds.SetRelation("Orders", "OrderDetails", "Id", "OrderId")
    
                    Master.DataSource = ds
                    Master.DataMember = ds.Tables(0).TableName
    
                    Details.DataSource = Master
                    Details.DataMember = ds.Relations(0).RelationName
    
                    OrderDetails.DataSource = Details
                    OrderDetails.DataMember = ds.Relations(1).RelationName
    
                    CustomerTable = ds.Tables("Customer")
                    Dim OrderTable As DataTable = ds.Tables("Orders")
    
                Catch ex As Exception
                    HasErrors = True
                    ExceptionMessage = ex.Message
                End Try
            End Using
        End Sub
        ''' <summary>
        ''' Add new order for a customer
        ''' </summary>
        ''' <param name="CustomerId">Identifies the customer for this order</param>
        ''' <param name="OrderDate"></param>
        ''' <param name="Invoice"></param>
        ''' <param name="NewPrimaryKeyValue">new primary key for new order row</param>
        ''' <remarks>
        ''' Here I'm using NewPrimaryKeyValue as success of the operations
        ''' while in AddCustomer I use a function returning a bool. I simply
        ''' wanted to show two variations on how one might write this code.
        ''' </remarks>
        Public Sub AddOrder(ByVal CustomerId As Integer, ByVal OrderDate As Date, ByRef Invoice As String, ByRef NewPrimaryKeyValue As Integer)
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
    
                    cmd.CommandText = "INSERT INTO Orders (CustomerId,OrderDate,Invoice) VALUES (@CustomerId,@OrderDate,@Invoice)"
    
                    Try
                        cn.Open()
    
                        cmd.Parameters.AddWithValue("@CustomerId", CustomerId)
                        cmd.Parameters.AddWithValue("@OrderDate", Now)
                        Invoice = GenerateInvoice(cn)
                        cmd.Parameters.AddWithValue("@Invoice", Invoice)
    
                        Dim result As Integer = cmd.ExecuteNonQuery()
                        If result = 1 Then
                            cmd.CommandText = "Select @@Identity"
                            NewPrimaryKeyValue = CInt(cmd.ExecuteScalar)
                        End If
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                        NewPrimaryKeyValue = -1
                    End Try
    
                End Using
            End Using
        End Sub
        ''' <summary>
        ''' We only permit order date changed as the invoice is a generated value that in my
        ''' cases a business rule to not permit the value to change.
        ''' </summary>
        ''' <param name="id"></param>
        ''' <param name="OrderDate"></param>
        ''' <returns></returns>
        Public Function UpdateOrder(ByVal id As Integer, OrderDate As Date) As Boolean
            Dim success As Boolean = False
    
            Dim sql As String = "UPDATE Orders  SET OrderDate = @OrderDate WHERE id = @Id"
    
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = sql}
    
                    cmd.Parameters.AddWithValue("@OrderDate", OrderDate)
                    cmd.Parameters.AddWithValue("@id", id)
    
                    Try
                        cn.Open()
                        success = cmd.ExecuteNonQuery = 1
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                    End Try
                End Using
            End Using
    
            Return success
    
        End Function
        ''' <summary>
        ''' Remove a single order
        ''' </summary>
        ''' <param name="OrderId">Primary key to identify a valid order record</param>
        Public Function RemoveSingleOrder(ByVal OrderId As Integer) As Boolean
            Dim success As Boolean = False
    
            Dim sql As String = "DELETE FROM [dbo].[Orders] WHERE id = @id"
    
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = sql}
    
                    cmd.Parameters.AddWithValue("id", OrderId)
    
                    Try
                        cn.Open()
                        success = cmd.ExecuteNonQuery = 1
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                    End Try
                End Using
            End Using
    
            Return success
    
        End Function
    
        ''' <summary>
        ''' Add a new customer
        ''' </summary>
        ''' <param name="FirstName"></param>
        ''' <param name="LastName"></param>
        ''' <param name="Address"></param>
        ''' <param name="City"></param>
        ''' <param name="State"></param>
        ''' <param name="ZipCode"></param>
        ''' <param name="NewPrimaryKeyValue">new primary key for newly added customer row</param>
        ''' <returns></returns>
        ''' <remarks>
        ''' See comments in AddOrder as I did this method different than AddOrder
        ''' to show variations.
        ''' </remarks>
        Public Function AddCustomer(ByVal FirstName As String, ByVal LastName As String, ByVal Address As String, ByVal City As String, ByVal State As String, ByVal ZipCode As String, ByRef NewPrimaryKeyValue As Integer) As Boolean
            Dim Success As Boolean = False
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "INSERT INTO Customer (FirstName,LastName,[Address],City,[State],ZipCode) VALUES (@FirstName,@LastName,@Address,@City,@State,@ZipCode)"
                    Try
                        cmd.Parameters.AddWithValue("@FirstName", FirstName)
                        cmd.Parameters.AddWithValue("@LastName", LastName)
                        cmd.Parameters.AddWithValue("@Address", Address)
                        cmd.Parameters.AddWithValue("@City", City)
                        cmd.Parameters.AddWithValue("@State", State)
                        cmd.Parameters.AddWithValue("@ZipCode", ZipCode)
                        cn.Open()
    
                        Dim result As Integer = cmd.ExecuteNonQuery()
                        If result = 1 Then
                            cmd.CommandText = "Select @@Identity"
                            NewPrimaryKeyValue = CInt(cmd.ExecuteScalar)
                            Success = True
                        End If
    
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                        NewPrimaryKeyValue = -1
                        Success = False
                    End Try
                End Using
            End Using
    
            Return Success
    
        End Function
        ''' <summary>
        ''' Remove customer (master) by primary key along with tha orders (childern).
        ''' To be safe a transation is used.
        ''' </summary>
        ''' <param name="id"></param>
        ''' <returns></returns>
        Public Function RemoveCustomerAndOrders(ByVal id As Integer) As Boolean
    
            Dim sql As String = "DELETE FROM Orders WHERE CustomerId =  @CustomerId"
            Dim success As Boolean = False
    
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                cn.Open()
    
                Dim trans As SqlTransaction = cn.BeginTransaction("DeleteOps")
    
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = sql, .Transaction = trans}
    
                    cmd.Parameters.AddWithValue("@CustomerId", id)
    
                    Try
                        cmd.ExecuteNonQuery()
                        cmd.Parameters.Clear()
                        cmd.Parameters.AddWithValue("@Id", id)
                        cmd.CommandText = "DELETE FROM Customer WHERE  id = @id"
                        cmd.ExecuteNonQuery()
                        trans.Commit()
                        success = True
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                        Try
                            trans.Rollback()
                        Catch transEx As Exception
                            HasErrors = True
                            ExceptionMessage = transEx.Message
                        End Try
                    End Try
                End Using
            End Using
    
            Return success
    
        End Function
        ''' <summary>
        ''' Update a customer
        ''' </summary>
        ''' <param name="CustomerRow"></param>
        ''' <returns></returns>
        Public Function UpdateCustomer(ByVal CustomerRow As DataRow) As Boolean
    
            Dim success As Boolean = False
    
            Dim sql As String = "UPDATE Customer  SET FirstName = @FirstName,LastName = @LastName,[Address] = @Address,City = @City,[State] = @State,ZipCode = @ZipCode WHERE id = @Id"
    
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = sql}
    
                    cmd.Parameters.AddWithValue("@FirstName", CustomerRow.Field(Of String)("FirstName"))
                    cmd.Parameters.AddWithValue("@LastName", CustomerRow.Field(Of String)("LastName"))
                    cmd.Parameters.AddWithValue("Address", CustomerRow.Field(Of String)("Address"))
                    cmd.Parameters.AddWithValue("@City", CustomerRow.Field(Of String)("City"))
                    cmd.Parameters.AddWithValue("@State", CustomerRow.Field(Of String)("State"))
                    cmd.Parameters.AddWithValue("@ZipCode", CustomerRow.Field(Of String)("ZipCode"))
                    cmd.Parameters.AddWithValue("@id", CustomerRow.Field(Of Integer)("id"))
    
                    Try
                        cn.Open()
                        success = cmd.ExecuteNonQuery = 1
                    Catch ex As Exception
                        HasErrors = True
                        ExceptionMessage = ex.Message
                    End Try
                End Using
            End Using
    
            Return success
    
        End Function
        ''' <summary>
        ''' Calls a database sequence in the database to get 
        ''' a unique invoice number
        ''' 
        ''' Requires a open connection as per above.
        ''' </summary>
        ''' <param name="cn"></param>
        ''' <returns></returns>
        Public Function GenerateInvoice(ByVal cn As SqlConnection) As String
    
            Dim result As String = ""
            Dim sql As String = "SELECT CONVERT(VARCHAR(4), GETDATE(), 12) + RIGHT('0000' + CAST( NEXT VALUE FOR dbo.GetInvoiceNumber AS VARCHAR(3)),4)"
    
            Using cmd As New SqlCommand With {.Connection = cn, .CommandText = sql}
                result = cmd.ExecuteScalar.ToString
            End Using
    
            Return result
    
        End Function
    
    End Class
    

    Using the edit function above in a form

    Private Sub EditCurrentCustomer()
        Dim CustomerRow As DataRow = CType(bsMaster.Current, DataRowView).Row
        Dim f As New CustomerForm(False, StateInformation, CustomerRow)
    
        Try
            If f.ShowDialog() = DialogResult.OK Then
                Dim ops As New Operations
                If Not ops.UpdateCustomer(CustomerRow) Then
                    MessageBox.Show($"Failed to update: {ops.ExceptionMessage}")
                End If
            End If
        Finally
            f.Dispose()
        End Try
    End Sub
    So it's not just about to use or not to use a function it's when to use a function and the reusability and value added to what you are coding. 


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Wednesday, March 22, 2017 11:10 PM
    Moderator
  • ...include a process or a function within my code


    Show an example of what exactly you mean please?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, March 22, 2017 11:14 PM
  • What you call a process is in the .Net culture called a method. 

    Including methods was the first step in programming history to divide main processes into sub-processes mainly done for readability.

    Currently that is just a little step, now we have projects which are in parts of solutions.

    Projects can include many classes which have endless methods.

     


    Success
    Cor

    Thursday, March 23, 2017 6:31 AM