passing enumeration parameter to generic (all enumeration) sub

J

JackRazz

Hi everyone,

I'm trying to figure out how to pass enumerations to subroutines by reference so that
I can return a changed enumerated value. For example, I have a UpdateProperty
function that could take all integer enumerations, set it, and return it's updated
value.

When I do something like: isDirty =
ControlSettingTemplates.UpdateProperty(CType(Me.WindowState, Integer),
CType(aControl.WindowState, Integer))

Friend Shared Function UpdateProperty(ByRef aControlSettingInteger As Integer,
ByRef aControlInteger As Integer) As Boolean
If aControlSettingInteger <> aControlInteger Then
aControlSettingInteger = aControlInteger
Return True
End If
End Function

But it won't work. The first one where I cast it to an integer properly passes the
value to the function, but doesn't return it. I'm pretty sure its because I casted,
which changed it from a ref to a value.
I could potentially have hundreds of different enumerations to pass,so I want to be
able to call the approperiate overloaded UpdateProperty(byte, integer, long, etc).

Is there a way I can cast the enumerated parameter so its still ByRef or create an
UpdateProperty that would accept all enumerated types and then handle based on its
underlying type? I hope what I want makes since.

Thanks - JackRazz
 
B

Bill McCarthy

Hi JackRazz,

No, basically you would have to pass the control, and specify which property to
change. You cannot pass in the value of that property, because even if you
change the value of that parameter, whether it be a reference type or a value
type, that does not set the actual contol's property.

To simplify it, what you are currently doing is :

Dim MyValue As SomeEnum = SomeControls.Property
MyValue = anothervalue

As you hopefully can see, you are changing the value that is in MyValue, not the
control's property.

Bill.
 
J

JackRazz

It works for integer values. Me.Top, Left, Width, and Height are working fine.
Enum's are the only issue. In the code below, UpdateProperty is updating the
ControlSettingTemplate object, not the control. Specifically, all properties are set
here except for the WindowState.

Public Function SavePersistantProperties(ByRef aControl As Form) As Boolean
Dim isDirty As Boolean
isDirty = ControlSettingTemplates.UpdateProperty(CType(Me.WindowState,
Integer), CType(aControl.WindowState, Integer))
'isDirty = ControlSettingTemplates.UpdateProperty(Me.ControlName,
aControl.WindowState)
If aControl.WindowState = FormWindowState.Normal Then
isDirty = ControlSettingTemplates.UpdateProperty(Me.Top, aControl.Top)
isDirty = ControlSettingTemplates.UpdateProperty(Me.Left, aControl.Left)
isDirty = ControlSettingTemplates.UpdateProperty(Me.Width,
aControl.Width)
isDirty = ControlSettingTemplates.UpdateProperty(Me.Height,
aControl.Height)
End If
Return isDirty

End Function




| Hi JackRazz,
|
| No, basically you would have to pass the control, and specify which property to
| change. You cannot pass in the value of that property, because even if you
| change the value of that parameter, whether it be a reference type or a value
| type, that does not set the actual contol's property.
|
| To simplify it, what you are currently doing is :
|
| Dim MyValue As SomeEnum = SomeControls.Property
| MyValue = anothervalue
|
| As you hopefully can see, you are changing the value that is in MyValue, not the
| control's property.
|
| Bill.
|
|
|
| | > Hi everyone,
| >
| > I'm trying to figure out how to pass enumerations to subroutines by reference
| so that
| > I can return a changed enumerated value. For example, I have a UpdateProperty
| > function that could take all integer enumerations, set it, and return it's
| updated
| > value.
| >
| > When I do something like: isDirty =
| > ControlSettingTemplates.UpdateProperty(CType(Me.WindowState, Integer),
| > CType(aControl.WindowState, Integer))
| >
| > Friend Shared Function UpdateProperty(ByRef aControlSettingInteger As
| Integer,
| > ByRef aControlInteger As Integer) As Boolean
| > If aControlSettingInteger <> aControlInteger Then
| > aControlSettingInteger = aControlInteger
| > Return True
| > End If
| > End Function
| >
| > But it won't work. The first one where I cast it to an integer properly
| passes the
| > value to the function, but doesn't return it. I'm pretty sure its because I
| casted,
| > which changed it from a ref to a value.
| > I could potentially have hundreds of different enumerations to pass,so I want
| to be
| > able to call the approperiate overloaded UpdateProperty(byte, integer, long,
| etc).
| >
| > Is there a way I can cast the enumerated parameter so its still ByRef or
| create an
| > UpdateProperty that would accept all enumerated types and then handle based on
| its
| > underlying type? I hope what I want makes since.
| >
| > Thanks - JackRazz
| >
| >
| >
| >
| >
| >
| >
| >
| >
|
|
 
B

Bill McCarthy

Hi JackRazz,

Ah, I forgot that is indeed a "feature" of Vb.NET. VB will write out the code
for the property set, if you pass a property as the parameter. so what it
actually does is create a temporary variable, pass that to the method, and on
return assigns that to the property set, eg:

Foo(byRef arg as Int32)

' callign foo
Foo(MyControl.SomeProperty)

'actually becomes
Dim tempVar as Int32 = MyControl.SomeProperty
Foo(tempVar)
MyControl.someProperty = tempVar


This *magic* is only done when the parameter is specified directly. Because the
argument you are passing in is an enum though, and you cannot implicitly cast
from an integer to an enum, then you have to overload the function so as it is
typed as that type of enum, otherwise the property is not assigned back to.

so one work around would be to overload the UpdateProperty method so as the
arguments are both as the given enum.

Another alternative, given that it appears you are trying to save the form's
state, is to use reflection.

Bill.
 
C

chris in grimsby

Bill McCarthy said:
Hi JackRazz,

Ah, I forgot that is indeed a "feature" of Vb.NET. VB will write out the code
for the property set, if you pass a property as the parameter. so what it
actually does is create a temporary variable, pass that to the method, and on
return assigns that to the property set, eg:

Foo(byRef arg as Int32)

' callign foo
Foo(MyControl.SomeProperty)

'actually becomes
Dim tempVar as Int32 = MyControl.SomeProperty
Foo(tempVar)
MyControl.someProperty = tempVar


This *magic* is only done when the parameter is specified directly. Because the
argument you are passing in is an enum though, and you cannot implicitly cast
from an integer to an enum, then you have to overload the function so as it is
typed as that type of enum, otherwise the property is not assigned back to.

so one work around would be to overload the UpdateProperty method so as the
arguments are both as the given enum.

Another alternative, given that it appears you are trying to save the form's
state, is to use reflection.

Bill.




reference
so that
want
to be
based on
its


1. Switch OPTION STRICT OFF
2. forget the CTYPE()
3. Dont listen to Bulls**t

Option Strict is meant to help you, not be a rod to beat yourself with.
 
B

Bill McCarthy

Hi Chris,

chris in grimsby said:
1. Switch OPTION STRICT OFF
2. forget the CTYPE()
3. Dont listen to Bulls**t

Option Strict is meant to help you, not be a rod to beat yourself with.


Good catch on the option strict off ! I would recommend setting that at file
level only, and try to move the code into a separate file, rather than turn
option strict off on a broadscale.
I think given the limited number of enums he was actually going to deal with, an
overloaded method would work just as well, and would not require turning option
strict off.

Most importantly, I think he should be aware of what the compiler is actually
doing, as his code :

Friend Shared Function UpdateProperty(ByRef aControlSettingInteger As
Integer,
ByRef aControlInteger As Integer) As Boolean
If aControlSettingInteger <> aControlInteger Then
aControlSettingInteger = aControlInteger
Return True
End If
End Function


actually becomes :

Friend Shared Function UpdateProperty(ByRef aControlSettingInteger As
Integer,
ByRef aControlInteger As Integer) As Boolean
aControlSettingInteger = aControlInteger
If aControlSettingInteger <> aControlInteger Then
Return True
End If
End Function

That is, for every property he passes in, it deos actually get set regardless of
the equality test. So this magic of VB can be very misleading.

Bill.
 
B

Bill McCarthy

BTW: those
isDirty = ControlSettingTemplates.UpdateProperty(...)
lines of code need to be
isDirty = isDirty Or ControlSettingTemplates.UpdateProperty(...)


Bill.
 
J

JackRazz

Thanks Bill and Chris for the help. Unfortunately, 'Option Explicit Off' doesn't
work when I remove the explicit casting as the compiler still doesn't know which
overloaded function to call. I thought boxing combined with references would work
correctly, but still no go. The reason I wanted to create generic routines for the
underlying enum data type is that there could be many different enum data types used.
Virtually all controls have properties that use enums. Additionally, I want to give
the customer of my component the ability to write their own templates for custom
controls and don't want them to do something like this:

Dim i As Integer = Me.WindowState
isDirty = ControlSettingTemplates.UpdateProperty(i,
CType(aControl.WindowState, Integer))
Me.WindowState = i


The above does work, but is certiantly not very elegant. So if anyone has any ideas,
I sure would appreciate it. Also, could C# handle this more cleanly?

Thanks - JackRazz




| BTW: those
| isDirty = ControlSettingTemplates.UpdateProperty(...)
| lines of code need to be
| isDirty = isDirty Or ControlSettingTemplates.UpdateProperty(...)
|
|
| Bill.
|
|
| | > It works for integer values. Me.Top, Left, Width, and Height are working
| fine.
| > Enum's are the only issue. In the code below, UpdateProperty is updating the
| > ControlSettingTemplate object, not the control. Specifically, all properties
| are set
| > here except for the WindowState.
| >
| > Public Function SavePersistantProperties(ByRef aControl As Form) As
| Boolean
| > Dim isDirty As Boolean
| > isDirty = ControlSettingTemplates.UpdateProperty(CType(Me.WindowState,
| > Integer), CType(aControl.WindowState, Integer))
| > 'isDirty = ControlSettingTemplates.UpdateProperty(Me.ControlName,
| > aControl.WindowState)
| > If aControl.WindowState = FormWindowState.Normal Then
| > isDirty = ControlSettingTemplates.UpdateProperty(Me.Top,
| aControl.Top)
| > isDirty = ControlSettingTemplates.UpdateProperty(Me.Left,
| aControl.Left)
| > isDirty = ControlSettingTemplates.UpdateProperty(Me.Width,
| > aControl.Width)
| > isDirty = ControlSettingTemplates.UpdateProperty(Me.Height,
| > aControl.Height)
| > End If
| > Return isDirty
| >
| > End Function
| >
| >
| >
| >
| > | > | Hi JackRazz,
| > |
| > | No, basically you would have to pass the control, and specify which property
| to
| > | change. You cannot pass in the value of that property, because even if you
| > | change the value of that parameter, whether it be a reference type or a
| value
| > | type, that does not set the actual contol's property.
| > |
| > | To simplify it, what you are currently doing is :
| > |
| > | Dim MyValue As SomeEnum = SomeControls.Property
| > | MyValue = anothervalue
| > |
| > | As you hopefully can see, you are changing the value that is in MyValue, not
| the
| > | control's property.
| > |
| > | Bill.
| > |
| > |
| > |
| > | | > | > Hi everyone,
| > | >
| > | > I'm trying to figure out how to pass enumerations to subroutines by
| reference
| > | so that
| > | > I can return a changed enumerated value. For example, I have a
| UpdateProperty
| > | > function that could take all integer enumerations, set it, and return it's
| > | updated
| > | > value.
| > | >
| > | > When I do something like: isDirty =
| > | > ControlSettingTemplates.UpdateProperty(CType(Me.WindowState, Integer),
| > | > CType(aControl.WindowState, Integer))
| > | >
| > | > Friend Shared Function UpdateProperty(ByRef aControlSettingInteger As
| > | Integer,
| > | > ByRef aControlInteger As Integer) As Boolean
| > | > If aControlSettingInteger <> aControlInteger Then
| > | > aControlSettingInteger = aControlInteger
| > | > Return True
| > | > End If
| > | > End Function
| > | >
| > | > But it won't work. The first one where I cast it to an integer properly
| > | passes the
| > | > value to the function, but doesn't return it. I'm pretty sure its because
| I
| > | casted,
| > | > which changed it from a ref to a value.
| > | > I could potentially have hundreds of different enumerations to pass,so I
| want
| > | to be
| > | > able to call the approperiate overloaded UpdateProperty(byte, integer,
| long,
| > | etc).
| > | >
| > | > Is there a way I can cast the enumerated parameter so its still ByRef or
| > | create an
| > | > UpdateProperty that would accept all enumerated types and then handle
| based on
| > | its
| > | > underlying type? I hope what I want makes since.
| > | >
| > | > Thanks - JackRazz
| > | >
| > | >
| > | >
| > | >
| > | >
| > | >
| > | >
| > | >
| > | >
| > |
| > |
| >
| >
|
|
 
B

Bill McCarthy

Hi JackRazz,

I would go about this a very different route. If you want customers to be able
to create their own templates, I would be looking at marking the properties with
a custom attribute, to indicate that the values need to be persisted or
compared, and do this all via reflection.

Oh, and no C# would not handle this any cleaner. In fact, Vb added a lot of
extra functionality that you have been using that C# does not have, such as the
setting of properties when passed directly ByRef.


bill.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top