I'm trying to create a class that can be CType'd to different types:
Option Strict Off
Public Class CInteger
Private Value As Integer
Public Sub New(value As Integer)
Me.Value = value
End Sub
Public Shared Widening Operator CType(ByVal value As CInteger) As Integer
Return value.Value
End Operator
'Commenting next operator makes compilation without errors
Public Shared Widening Operator CType(ByVal value As CInteger) As String
Return value.Value
End Operator
End Class
Public Enum EEnum1 As Integer
First = 1
End Enum
Public Enum EEnum2 As Integer
First = 1
End Enum
Private Sub Test()
Dim e1 As EEnum1 = New CInteger(1)
Dim e2 As EEnum2 = New CInteger(1)
End Sub
It works fine converting to Enums if there's only and Integer operator defined, but when I try to add any other operator the compiler throws errors because the conversion can't be done.
I can neither change the Enum declarations nor declare CType operator for each Enum, is it posible to workaround this?
Related
InputValue1,..OperationAdd are instances of the class InputNumber. How do I assign my Inputvalues to the corresponding textboxes as option Strict On is activated?
Class MainWindow
Dim InputValue1 As New InputNumber
Dim InputValue2 As New InputNumber
Dim ExpectedResultValue As New InputNumber
Dim OperationAdd As New InputNumber
Private Sub TBoxNumber1_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TBoxNumber1.TextChanged
TBoxNumber1.Text = InputValue1 'There is an error in this line, value of type InputNumber 'cannot be converted to a string
End Sub
Below is the InputNumber Class:
Public Class InputNumber
Inherits Input
Private _number As Integer
Public Property Number As Integer
Get
Return _number
End Get
Set(value As Integer)
_number = value
End Set
End Property
Protected Overrides Function Validate(s As String) As Boolean
Dim isValid As Boolean = Integer.TryParse(s, _number)
Return isValid
End Function
End Class
It seems to me that you should be getting the input from the TextBox into your InputNumber object, not the other way around. This:
TBoxNumber1.Text = InputValue1
should probably be this:
InputValue1.Validate(TBoxNumber1.Text)
When it actually comes time to display the value of that InputNumber, you would have to use InputValue1.Number.ToString(). Personally, I would add this to your InputNumber class:
Public Overrides Function ToString() As String
Return Number.ToString()
End Function
and then you can use InputValue1.ToString() instead.
EDIT:
It's been pointed out that the Validate method is Protected so it can't be called like that. Unless there's some use for it in the Input base class, I'm not sure what it's for because, as it stands, you'd need to validate externally anyway, e.g.
Dim number As Integer
If Integer.TryParse(TBoxNumber1.Text, number) Then
InputValue1.Number = number
End If
I am questioning the implementation of InputNumber. It does not make much sense in the current form. We don't know when validation is happen and Number is integer in fact.
I would do something like this.
Public Class InputNumber
Private _number As Integer
Private _hasNumber As Boolean
Public Sub New(s As String)
SetNumber(s)
End Sub
Public Sub New()
End Sub
Public ReadOnly Property Number As Integer
Get
Return _number
End Get
End Property
Public ReadOnly Property HasNumber As Boolean
Get
Return _hasNumber
End Get
End Property
Public Sub SetNumber(s As String)
_hasNumber = Integer.TryParse(s, _number)
End Sub
' For consistency...
Public Sub SetNumber(i As Integer)
_hasNumber = true
_number = i
End Sub
Public Overrides Function ToString() As String
If HasNumber Then Return Number.ToString()
Return String.Empty
End Function
End Class
Then your usage will be (and I agree with #jmcilhinney, when you have TextChange event, you want to take a value from the text box and set a variable)
Dim inp As New InputNumber("ddd")
txtBox1.Text = If(inp.HasNumber, inp.Number.ToString(), "NO VALUE") '' example to use HasNumber
inp.SetNumber("sss")
txtBox2.Text = inp.ToString() '' Example to use straight value
inp.SetNumber(10)
Dim current As Integer = If(inp.HasNumber, inp.Number, -1) '' using as numeric value
Now, this class makes slightly more sense
I want to use named error codes within my app. This should ensure, that every developer does not confuse numeric-only error codes with other codes, and also reduces the time a developer needs to realize what the error code should represent.
Compare this example:
Function New() As Integer
Return 0
End Function
with this example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
Of course, I could let the developers write like the following:
Function New() As Integer
Return 0 ' ERROR_SUCCESS
End Function
However, the code above raises a pitfall when a developer updates the actual return code but forgets about the comment. Some developer look at the actual return code and some at the comment. I want to mitigate that confusion.
I come up the following class (extract):
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Now I want to use this ErrorCodes class like in the following example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
As expected, I will produce an exception (type conversion) since the actual value I return is a instance of the class ErrorCodes instead of the generic data type Integer.
As you can see with the ToString() function, I let the class automatically/implicitly converts the instanced object into the generic data type String, when the class instance is assigned to a String typed variable.
Is there a way to do the same with the generic data type Integer like I did with ToString()?
I am using the .NET Framework 4.0, as for compatibility reasons with Windows XP SP3.
Another way to say what I want:
Dim stringVariable As String = ErrorCodes.ERROR_SUCCESS ' should be "[0]ERROR_SUCCESS".
Dim integerVariable As Integer = ErrorCodes.ERROR_SUCCESS ' should be 0.
I do not want to trigger implicit conversion warnings/errors, or to force the developer to typecast explicitly.
Yes you can do that with the use of Conversion Operators.
Here is the code:
Public Class Form1
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared Widening Operator CType(ByVal ec As ErrorCodes) As String
Return ec.ToString
End Operator
Public Shared Narrowing Operator CType(ByVal ec As ErrorCodes) As Integer
Return ec.Value
End Operator
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Public Shared ReadOnly ERROR_FAILED As ErrorCodes = New ErrorCodes("ERROR_FAILED", 1)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim em As String = ErrorCodes.ERROR_SUCCESS
Dim ev As Integer = ErrorCodes.ERROR_SUCCESS
Dim mm As String = String.Format("String: {0}, Value: {1}", em, ev)
MsgBox(mm)
End Sub
End Class
More info here
Hope this helps.
This, as jmcilhinney pointed out, uses Enums and the Description attribute.
Here is the class
'requires
' Imports System.Reflection
' Imports System.ComponentModel
Public Class ErrorCodes
Public Enum ErrCode 'these are the error codes
'note that the codes should be unique
<Description("Success")> ERROR_SUCCESS = 0
<Description("Error A")> ERROR_A = 1
End Enum
Public Class InfoForErrCode
Public TheDescription As String
Public TheValue As Integer
Public AsString As String
End Class
Public Shared Function Info(TheError As ErrCode) As InfoForErrCode
Dim rv As New InfoForErrCode
rv.TheDescription = GetDescription(TheError)
rv.TheValue = TheError
rv.AsString = TheError.ToString
Return rv
End Function
Private Shared Function GetDescription(TheError As ErrCode) As String
Dim rv As String = ""
Dim fi As FieldInfo = TheError.GetType().GetField(TheError.ToString())
Dim attr() As DescriptionAttribute
attr = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute),
False), DescriptionAttribute())
If attr.Length > 0 Then
rv = attr(0).Description
Else
rv = TheError.ToString()
End If
Return rv
End Function
End Class
And here is how it can be used
Dim foo As ErrorCodes.ErrCode = ErrorCodes.ErrCode.ERROR_SUCCESS
Dim inf As ErrorCodes.InfoForErrCode = ErrorCodes.Info(foo)
Stop 'examine inf
foo = ErrorCodes.ErrCode.ERROR_A
inf = ErrorCodes.Info(foo)
Stop 'examine inf
I have a problem with an Generic Class and define the operator overloads associated with it.
Question:
How do I set the operator for the following class assuming that the DataType will be any of the numeric types {float,double,Integer,etc.}?
I quite don't understand the concept yet
Public Class Nombre(Of DataType) '' aka Number
'VALUE
Private _Value As DataType
Public Property Value As DataType
Get
Return Me._Value
End Get
Set(value As DataType)
Me._Value = value
End Set
End Property
Public Sub New(value As DataType)
Me._Value = value
End Sub
Public Sub Add(x As DataType)
_Value += x
End Sub
Public Sub Subs(x As DataType)
_Value -= x
End Sub
Public Sub Mult(x As DataType)
_Value = _Value * x
End Sub
Public Sub Power(x As DataType)
_Value = _Value ^ x
End Sub
Public Sub inc()
_Value += 1
End Sub
Public Sub dec()
_Value -= 1
End Sub
Public Sub Divide(x As DataType)
_Value = _Value / x
End Sub
End Class
How do I set the operator for the following class assuming that the DataType will be any of the numeric types {float,double,Integer,etc.}?
You can't do that in a type-safe way, since you cannot restrict DataType to classes where +, -, etc. are defined. This is a commonly requested feature which is just not available yet.
You will have to create an IntegerNombre class, a DoubleNombre class, etc. Then you can define operator overloads in the usual way:
Public Shared Operator +(ByVal n1 As IntegerNombre,
ByVal n2 As IntegerNombre) As IntegerNombre
Return New IntegerNombre(n1._Value + n2._Value)
End Operator
(Of course, you could keep your generic class, turn Option Strict Off and use late binding with Object:
_Value = DirectCast(_Value, Object) + x
...but you really shouldn't.)
Currently I lot of code spent converting Strings into numbers and checking that those numbers are valid. So I'm trying to create a class to simplify this.
I created two Widening CType Operators to simplify assigning the class to either the number Type or a string. But I've run into a problem. When adding the Constrained number to a collection of objects, these CType operators are not called so the actual ConstrainedNumber object is added to the collection. Obviously the database does not support custom types like this. VBNet will not allow me to create a CType operator for when the class is cast to an Object.
What I need is some way to cause a compiler error or warning if it is being cast to an object. Is there an Annotation that could specify this? Or better yet, a way to override the CType Operator so I can convert to an object?
Here's the code:
Friend Class ConstainedNumber(Of TNum As Structure)
Private Property _number As Object
Private Property _nDefaultValue As TNum
Private ReadOnly _nMax As Double
Private ReadOnly _nMin As Double
Private ReadOnly _bCanEqualMin As Boolean
Private ReadOnly _bCanEqualMax As Boolean
Public Function IsValid() As Boolean
Return IsValid(_number)
End Function
Private Function IsValid(value As Object) As Boolean
Return isValidNumber(value, _nMax, _nMin, _bCanEqualMax, _bCanEqualMin)
End Function
Public Property num As TNum
Get
Return If(IsValid, CType(_number, TNum), _nDefaultValue)
End Get
Set(value As TNum)
If IsValid(value) Then
_number = value
End If
End Set
End Property
Public Property str As String
Get
Return If(IsValid, _number.ToString, String.Empty)
End Get
Set(value As String)
If IsValid(value) Then
_number = Decimal.Parse(value)
End If
End Set
End Property
Public WriteOnly Property Val As Object
Set(value As Object)
If isValidObject(value) Then
str = value.ToString
End If
End Set
End Property
Public Sub New(defaultValue As TNum, nMax As Double, nMin As Double, Optional bCanEqualMax As Boolean = False, Optional bCanEqualMin As Boolean = False)
_nMax = nMax
_nMin = nMin
_bCanEqualMax = bCanEqualMax
_bCanEqualMin = bCanEqualMin
_nDefaultValue = defaultValue
num = defaultValue
End Sub
Public Function ToString() as String
Return str
End Function
Public Shared Widening Operator CType(ByVal value As ConstainedNumber(Of TNum)) As TNum
Return value.num
End Operator
Public Shared Widening Operator CType(ByVal value As ConstainedNumber(Of TNum)) As String
Return value.ToString()
End Operator
'//Here is the Issue. This CANNOT be done apparently.
Public Shared Widening Operator CType(ByVal value As ConstainedNumber(Of TNum)) As Object
Return value.num
End Operator
End Class
Here is a usage Example
Friend Class BasicSearchParams
Public Property sKeyword As String = String.Empty
Public ReadOnly dblLatitude As New ConstainedNumber(Of Double)(NoValueDouble, 90, -90, True, True)
Public ReadOnly dblLongitude As New ConstainedNumber(Of Double)(NoValueDouble, 180, -180, True, True)
Public ReadOnly dblPriceFrom As New ConstainedNumber(Of Double)(0, Double.MaxValue, 0)
Public ReadOnly dblPriceTo As New ConstainedNumber(Of Double)(0, Double.MaxValue, 0)
Public ReadOnly nListingsPerPage As New ConstainedNumber(Of Short)(1, 10000, 0) With {.Val = cGlobals.DefaultListingsPerPage}
Public ReadOnly nPictureWidth As New ConstainedNumber(Of Integer)(0, Short.MaxValue, 0)
Public ReadOnly nPictureHeight As New ConstainedNumber(Of Integer)(0, Short.MaxValue, 0)
End Class
Another goal I originally had, but it doesn't appear to be possible, is to have "num" be a default property without having a Parameter. I tried the annotation below but it doesn't work.
<System.Reflection.DefaultMember("num")>
Most of the search results I've found have turned up to be the opposite of what I'm looking for so here's my question:
I'm trying to convert System types into custom types of my own but as I mentioned, my search results have not been effective and give me the opposite of what i'm looking for.
Say I have a String of "mystringgoeshere" and a class like:
Class MyStringType
Dim str As String
End Class
Dim s As MyStringType = "mystringgoeshere"
And i get this error {Value of type 'String' cannot be converted to 'Project1.MyStringType'.}
I don't have any code yet really because I have no idea how to achieve this, but essentially what I want to do is set the "s" object's "str" string using a method like what i have in the code block above. I've tried using a "new(data as String)" subroutine, but it doesn't work with what i am trying.
Any ideas? thx~
Looking at this VBCity Article on creating Custom Types It is using the Widening Operator.
from last link:
Widening conversions always succeed at run time and never incur data loss. Examples are Single to Double, Char to String, and a derived type to its base type.
so try something like this
Public Class Form1
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim s As MyStringType = "mystringgoeshere"
Dim s1 As MyStringType = "Hello"
Dim s2 As MyStringType = s1 + s
End Sub
End Class
Class MyStringType
Private _string As String
Private Sub New(ByVal value As String)
Me._string = value
End Sub
Public Shared Widening Operator CType(ByVal value As String) As MyStringType
Return New MyStringType(value)
End Operator
Public Overrides Function ToString() As String
Return _string
End Function
Public Shared Operator +(ByVal s1 As MyStringType, s2 As MyStringType) As MyStringType
Dim temp As String = s1._string + s2._string
Return New MyStringType(temp)
End Operator
End Class
just change ur code little bit like this :
Class MyStringType
Dim str As String
Sub New(ByVal str1 As String)
str = str
End Sub
End Class
Dim s As New MyStringType("abhi")
what you should do is
Class MyStringType
Dim str As String
End Class
Dim s As MyStringType
s.str = "mystringgoeshere"
It sounds like you want to subclass System.String. This is a fundamental of OOP programming. Inheritance is PRETTY important.
http://en.m.wikipedia.org/wiki/Inheritance_(object-oriented_programming)