Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Can someone explain why I would do this code this way?
I Have a small grasp of delegates but don't understand the advantages
Can some one try and help explain what I am doing here. I am very new to classes and delegates. Just need some help.
Here is my delegate code
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click
Dim NewCompare As New Compare
NewCompare.Num1 = 3
NewCompare.Num2 = 2
NewCompare.CheckCompare(AddressOf GreaterThan)
NewCompare.CheckCompare(AddressOf SmallerThan)
End Sub
Function GreaterThan(Num1 As Integer, Num2 As Integer) As Boolean
Return Num1 > Num2
End Function
Function SmallerThan(Num1 As Integer, Num2 As Integer) As Boolean
Return Num1 < Num2
End Function
End Class
Class Compare
Property Num1 As Integer
Property Num2 As Integer
Delegate Function CompareValues(Num1 As Integer, Num2 As Integer) As Boolean
Public Sub CheckCompare(compare As CompareValues)
If compare(_Num1, _Num2) Then
MsgBox(_Num1)
Else
MsgBox(_Num2)
End If
End Sub
End Class
Well, "the essential idea" of "delegation" is simply: "identify Someone Else that you can ask."
In this example, the Compare class exists to "compare two objects." But you've said that it is to delegate that responsibility to some other function that is not a part of its own definition. Furthermore, you specify exactly what an acceptable "delegate function" must look like.
The Delegate Function declaration specifies what that delegate must look like. "An acceptable delegate must return a Boolean, and it must accept (exactly ...) two Integer parameters." The language ensures, at compile-time, that this is so.
In your two, separate, calls to the CheckCompare method of the Compare class, you provide separate references to two functions, GreaterThan and LessThan, both of which are conformant to the strictures set out in the Delegate Function declaration. Therefore, the language permits them to be used in the calls. And, as instructed, the CheckCompare method invokes the delegate-function that it has been given, when told to do so.
It does not know (but, it does not care) exactly which delegate it is. The language ensures that "an acceptable delegate" has been provided, and all this method needs to do, is to call "it."
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Trying to create a universal placeholder for all methods in my class instead of having to declare multiple varibles per class, else declaring multiple instances of a class and using its methods can be quite costly
dim beginIndex, endIndex as integer
public sub GetLastFiveLetters(str as string)
' assume string is 10 characters long
beginIndex = 5
endIndex = 10
ResetVariable() 'I want beginIndex and endIndex to be 5 and 10 after I call this method
return = str.substring(5, 10)
end sub
public sub GetFirstFiveLetters(str as string)
'assume string is 10 characters long
beginIndex = 0
endIndex = 5
ResetVariable() 'I want beginIndex and endIndex to be 0 and 5 after I call this method
return = str.substring(0, 5)
end sub
public sub ResetVariables()
beginIndex = 0
endIndex = 0
end sub
The reset variable method is simply there for example purposes, what i want to do is be able to use a variable with multiple values across multiple methods...
So when i call reset variable, even though im technically reseting the variable across all methods, i want to variables to retain their method specific values ... so in the first method even though i called the reset method, i want beginIndex to still be 5 and endIndex to still be 10, it is only in the resetvariable method where beginIndex will be 0 and endIndex will be 0
Regarding storing variables in methods:
... declaring multiple instances of a class and using its methods can be quite costly
WRONG. Variables declared in methods, i.e. local variables, exist only while the method is being executed. On the other hand, variables declared at the class level, i.e. fields, exist for each class instance or object for its the whole life time.
You must make a distinction between the variable declaration and the memory that a variable uses at runtime. The variable declaration itself is not compiled into code. Only the variable accesses (i.e. setting or reading the variable) are. At runtime, local variables start to exist when a method is called and cease to exist after the method returns.
Class fields, however, exist as long as the objects exist, whether a method is being called or not.
Specifically aimed at winforms development.
I suspect that the answer to this is probably No but S.O. has a nice way of introducing me to things I didn't know so I thought that I would ask anyway.
I have a class library with a number of defined methods therein. I know from personal experimentation that it is possible to get information about the application within which the class library is referenced. What I would like to know is whether it would be possible to get information about the value of a property of a control on a form when a routine on that form calls a method in my class library without passing a specific reference to that form as a parameter of the method in the class library?
So purely as an example (because it's the only thing I can think of off the top of my head). Is there a way that a message box (if it had been so designed to do so in the first place) could 'know' from which form a call to it had been made without that form being specifically referenced as a parameter of the message box in the first place?
Thanks for any insights you might have.
To address the example of the MessageBox, in many of the cases you can use the active form. You can retrieve it by using Form.ActiveForm. Of course, as regards the properties that you can request, you are limited to the properties provided by the Form or an interface that the Form implements and that the method in the other assembly also knows. To access other properties you can use Reflection, but this approach would neither be straightforward nor would it be clean.
In a more general scenario, you could provide the property value to the method as a parameter. If it is to complex to retrieve the value of the property and the value is not needed every time, you can provide a Func(Of TRESULT) to the method that retrieves the value like this (sample for an integer property):
Public Sub DoSomethingWithAPropertyValue(propValFunc As Func(Of Integer))
' Do something before
If propertyValueIsNeeded Then
Dim propVal = propValFunc()
End If
' Do something afterwards
End Sub
You call the method like this:
Public Sub SubInForm()
Dim x As New ClassInOtherAssembly()
x.DoSomethingWithAPropertyValue(Function() Me.IntegerProperty)
End Sub
I kind of question your intentions. There's no problem sending the information to a function or the constructor.
Instead of giving the information to the class, the class would ask for the information instead using an event.
Module Module1
Sub Main()
Dim t As New Test
AddHandler t.GetValue, AddressOf GetValue
t.ShowValue()
Console.ReadLine()
End Sub
Public Sub GetValue(ByRef retVal As Integer)
retVal = 123
End Sub
End Module
Class Test
Public Delegate Sub DelegateGetValue(ByRef retVal As Integer)
Public Event GetValue As DelegateGetValue
Public Sub ShowValue()
Dim val As Integer
RaiseEvent GetValue(val)
Console.WriteLine(val)
End Sub
End Class
My question is, when calling a generic method in vb I am used to having to state what type i am passing. Example 3. I am running VS 2012 and now I dont have to do this. Example 2. My question is when did this change, and how is this working(is the compiler reflecting the type to put in and letting me be lazy)?
Public function Foo(of T)(bar as T) As Boolean
return true
end function
Example 2
public sub TestFoo()
dim test as int = 0
Foo(test)
end sub
Example 3
public sub TestFoo()
dim test as int = 0
Foo(of int)(test)
end sub
The compiler simply infers what type to use. This feature was available when generics were introduced.
Example 2 and 3 still exist in VS2012, they are simply 2 different implementations. One is using a Generic declaration the other is not.
Here is a good example: Explain Generics in layman style in C#?
I'm trying to create a a simple function in VB.net which will take a few parameters for use with TryCast.
My goal is to have a function I can use in place of TryCast which instead of returning Nothing when it fails it should return DbNull.
I just can't seem to get anything to work despite much searching.
Thanks.
The problem is that you have to have some specific return type for your function. So you can write a function with a signature like this:
Public Function TryCast(Of T)(ByVal item As Object) As T
But you will never be able to make it do what you want, because the type of T is never going to be DBNull (okay, maybe it could happen, but hopefully you get the idea).
Put another way, the type system blocks this. On the one hand, you want to be perfectly explicit about the return type (hence, the cast). On the other hand, you want to be able to return a completely different type. .Net does not allow this, even with dynamic typing. Either a method returns a single fixed type, or it is not declared to return a type at all.
With Option Explicit turned off, you might be able to go for something like this:
Public Function TryCast(Of T)(ByVal item As Object)
However, I don't think this will do what you want, either, because now the returned value is effectively the same as object, and you lose the benefit of any casting.
It works with the normal TryCast() for Nothing, because Nothing can be assigned to any type. DBNull is itself a fixed type, and so is not as flexible.
Simple answer - not possible, and here is why. Suppose you have the following code:
Class A
End Class
Class B : Inherits A
End Class
Class C
End Class
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim aaa As A = MyTryCast(Of A)(New B)
Dim ccc As C = MyTryCast(Of B)(New C)
End Sub
Private Function MyTryCast(Of T As Class)(obj As Object) As Object
Dim result As Object = TryCast(obj, T)
If result Is Nothing Then Return Convert.DBNull
Return result
End Function
MyTryCast does exactly what you are asking for, so aaa assignment works. Problem appears when you assign DBNull to ccc variable of type C. You would expect it to assign DBNull to C, because C cannot be converted to B (regular TryCast would return Nothing). Instead, you get System.InvalidCastException, because you cannot assign a DBNull to an instance of your custom class. Important thing to remember here - Nothing can be assigned to anything, DBNull can only be assigned to an Object. See here for DBNull inheritance hierarchy.
I was shocked just a moment ago to discover that the following is legal (the C# equivalent is definitely not):
Class Assigner
''// Ignore this for now.
Public Field As Integer
''// This part is not so weird... take another instance ByRef,
''// assign it to a different instance -- stupid but whatever. '
Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
x = y
End Sub
''// But... what's this?!?
Sub AssignNew()
''// Passing "Me" ByRef???
Assign(Me, New Assigner)
End Sub
''// This is just for testing.
Function GetField() As Integer
Return Me.Field
End Function
End Class
But what's even stranger just as strange to me is that it doesn't seem to do what I expect:
Dim a As New Assigner With {.Field = 10}
a.AssignNew()
Console.WriteLine(a.GetField())
The above outputs "10," not "0" like I thought it would (though naturally, this expectation was itself infused with a certain kind of horror). So it seems that you can pass Me ByRef, but the behavior is somehow overridden (?) by the compiler to be as if you had passed Me ByVal.
Why is it legal to pass Me ByRef? (Is there some backwards-compatibility explanation?)
Am I correct in saying that the behavior of doing this is overridden by the compiler? If not, what am I missing?
This behavior actually follows pretty directly from the Visual Basic specification.
11.4.3 Instance Expressions
An instance expression is the keyword Me, MyClass, or MyBase. An instance expression, which may only be used within the body of a non-shared method, constructor, or property accessor, is classified as a value.
9.2.5.2 Reference Parameters
If the type of the variable being passed to a reference parameter is not compatible with the reference parameter's type, or if a non-variable is passed as an argument to a reference parameter, a temporary variable may be allocated and passed to the reference parameter. The value being passed in will be copied into this temporary variable before the method is invoked and will be copied back to the original variable (if there is one) when the method returns.
(All emphasis mine)
So, the compiler will create a temporary variable assigned to the value of Me to be passed as the ByRef parameter. Upon return, no copy of the resulting value will take place since Me is not a variable.
It appears the compiler transforms "Me" into a variable which is then passed ByRef. If you compile your code, then open it with Reflector, you can see what's happening:
Class Assigner
''// Methods
Public Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
x = y
End Sub
Public Sub AssignNew()
Dim VB$t_ref$S0 As Assigner = Me
Me.Assign((VB$t_ref$S0), New Assigner)
End Sub
Public Function GetField() As Integer
Return Me.Field
End Function
''// Fields
Public Field As Integer
End Class
So it looks like when you call AssignNew(), you are assigning the new instance to the internally generated variable. The "a" variable doesn't get touched because it's not even a part of the function.
This is just one of the thousands of possible 'almost errors' a programmer can make. MS caught most of them, in fact, sometimes I'm suprised at how many warnings do come up.
they missed this one.
As far as why it doesn't change 'me', it's a darn good thing! When you use 'me', it just passes a copy of the real class you are working with, for safety purposes. If this worked they way you were hoping, we would be talking GIANT side-effect. You're innocently working away with in your class' methods, and them BAM all of a sudden you are in an ENTIRELY different object! That would be awful! If you're going to do that, you might as well just write a piece of spagetti MS-Basic line-numbered code with all globals that get randomly set, and no subs/functions.
The way this works is the same way if you pass arguments in parenthesis. For example this works as expected:
Assign(Reference_I_Want_To_Set, New Assigner)
But this doesn't change anything:
Assign((Reference_I_Want_To_Set), New Assigner)
If you reflect the above type of code as adam101 suggests you will see similar results. While that is huge frustration with the parenthesis, it is a very good thing with Me !!!
what you need to do to make this code work is this:
Class Assigner
''// Ignore this for now.
Private newPropertyValue As Integer
Public Property NewProperty() As Integer
Get
Return newPropertyValue
End Get
Set(ByVal value As Integer)
newPropertyValue = value
End Set
End Property
''// This part is not so weird... take another instance ByRef,
''// assign it to a different instance -- stupid but whatever. '
Shared Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
x = y
End Sub
''// But... what's this?!?
Shared Sub AssignNew(ByRef x As Assigner)
''// Passing "Me" ByRef???
Assign(x, New Assigner)
End Sub
End Class
then use it like
Dim a As New Assigner With {.NewProperty = 10}
Assigner.AssignNew(a)
my understanding is you cannot change the reference of the object while using it, so you need to change it in a shared sub
since Me cannot be the target of an assignment, the code seem to create a copy of it and from that point on, your not using the real object, but a copy of it