Best way to convert object to integer - vb.net

I wish to safely convert an object from an external cache to an Integer type.
The only way I can seem to do this is inside a try catch block like so:
Try
Return Convert.ToInt32(obj)
Catch
'do nothing
End Try
I hate writing catch statements like this.
Is there a better way?
I have tried:
TryCast(Object, Int32)
Doesn't work (must be reference type)
Int32.TryParse(Object, result)
Doesn't work (must be a string type)
UPDATE
I like the comment posted by Jodrell - this would make my code look like this:
Dim cacheObject As Object = GlobalCache.Item(key)
If Not IsNothing(cacheObject) Then
If TypeOf cacheObject Is Int32 Then
Return Convert.ToInt32(cacheObject)
End If
End If
'Otherwise get fresh data from DB:
Return GetDataFromDB

Clarification: the question was originally tagged c# vb.net; the following applies to C# only (although may be translated into VB.NET):
If it is a boxed int, then:
object o = 1, s = "not an int";
int? i = o as int?; // 1, as a Nullable<int>
int? j = s as int?; // null
so generalising:
object o = ...
int? i = o as int?;
if(i == null) {
// logic for not-an-int
} else {
// logic for is-an-int, via i.Value
}

Unesscessary conversion to String should be avoided.
You could use Is to check the type beforehand
Dim value As Integer
If TypeOf obj Is Integer Then
value = DirectCast(obj, Integer)
Else
' You have a problem
End If
or,
You could implement a variation on TryCast like this,
Function BetterTryCast(Of T)(ByVal o As Object, ByRef result As T) As Boolean
Try
result = DirectCast(o, T)
Return True
Catch
result = Nothing
Return False
End Try
End Function
Which you could use like this
Dim value As Integer
If BetterTryCast(obj, value) Then
// It worked, the value is in value.
End If

The simplest one is
Int32.TryParse(anObject.ToString, result)
Every Object has a ToString method and calling Int32.TryParse will avoid a costly (in terms of perfomance) exception if you Object is not a numeric integer. Also the value for result, if the object is not a string will be zero.
EDIT. The answer from Marc Gravell raised my curiosity. Its answer seems complex for a simple conversion, but it is better? So I have tried to look at the IL code produced by its answer
object o = 1, s = "not an int";
int? i = o as int?; // 1, as a Nullable<int>
int? j = s as int?; // null
IL CODE
IL_0000: ldc.i4.1
IL_0001: box System.Int32
IL_0006: stloc.0 // o
IL_0007: ldstr "not an int"
IL_000C: stloc.1 // s
while the IL CODE produced by my answer is the following
IL_0000: ldc.i4.1
IL_0001: box System.Int32
IL_0006: stloc.0 // anObject
IL_0007: ldloc.0 // anObject
IL_0008: callvirt System.Object.ToString
IL_000D: ldloca.s 01 // result
IL_000F: call System.Int32.TryParse
Definitively the answer from Marc is the best approach. Thanks Marc to let me discover something new.

this works:
Int32.TryParse(a.ToString(), out b);

Related

Stack too deep, try using less variables on creating contract

I am trying to create a contract from a contract factory using the following function:
function createContract(string _var1, string _var2,
uint32 _var3, string _var4, string _var5,
string _var6, uint32 _var7, uint32 _var8, uint32 _var9,
uint32 _var10, uint32 _var11)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6, _var7, _var8,
_var9, _var10, _var11);
}
N.B. random1 and random2 are fields in the contract factory.
This function throws Stack too deep, try using less variables. I have read that I should split up the function etc. to get around this, but obviously, that is not an option here. Is there a way to get this working?
So, initially I tried grouping the variables by type into this:
function createContract(string[] _var1, uint32[] _var2)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2);
}
However, nested dynamic arrays are not supported at this time. As string is represented as byte[] in EVM, a string[] is in fact passed as a byte[][].
I ended up grouping the uint32 and leaving the strings:
function createContract(string _var1, string _var2, uint32[] _var3,
string _var4, string _var5, string _var6)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6);
}
EDIT: Even though this method works, it is badly designed. See my other answer for a better workaround for this.
I went one step further with this as having an array of unit32 is ambiguous and confusing in terms of the position of a specific argument.
My final attempt utilized the struct type to provide a less ambiguous implementation. This struct is in a library in a separate file Library.sol:
struct ContractArgs {
uint32 var1;
string var2;
uint32 var3;
....
}
The factory method looks like this:
function createContract(Library.ContractArgs _contractArgs)
public returns (address contractAddress) {
return new Contract(_contractArgs, random1, random2);
}
And my constructor looks like this:
function Contract(Library.ContructorArgs _contractorArgs,
uint32 _supplierId, string _supplierName) {
contractArgs = _contractArgs;
random1 = _random1;
random2 = _random2;
}

Is it a waste of time to call a function in the foreach definition?

Sometimes I have to run a loop where the list or array comes from a function.
I usually do it this way :
Dim list = SomeClass.GetMyList()
For Each item in list
'Do some stuff
Next
Is it the same as :
For Each item in SomeClass.GetMyList()
'Do some stuff
Next
I usually do the first way because I think that second way makes a call everytime it starts the next iteration, therefore wasting some time.
Am I right to think that way ? Or can I go ahead with second way as the compiler is smart enough not to make a call every round ?
Only what is within the for block gets repeated, not its initialiser.
Your 2nd option does the same as the 1st, just with an unnamed temporary variable holding the result of GetMyList(). If anything, it might be more efficient for that reason... though a good optimiser would make both pieces of code equivalent anyway.
As mentioned in the comments, a debugger would've made this abundantly clear, and is an invaluable tool for countless other reasons.
Method #1 leaves you with a reference to the list in the scope of the rest of the method.
Method #2 creates a variable behind the scenes referencing the list, but that variable is out of scope after the for loop
For scoping I would prefer #2, but I am also impartial to succinct code. If GetMyList returns a reference type such as a List<T> or array, this could leave the door open to some unintended side effects.
Public Sub Foo()
Dim someClass As New SomeClass()
' this variable stays in scope after the following For Each loop
Dim list = someClass.GetMyList()
For Each item In list
Console.Write(item)
Next
Console.WriteLine()
' now we can sort the backing field - did you intend for this to happen?
list.Sort()
' the following For Each loop doesn't leave any reference behind
For Each item In someClass.GetMyList()
Console.Write(item)
Next
End Sub
Private Class SomeClass
Private _list As List(Of Integer) = {3, 2, 1}.ToList()
Public Function GetMyList() As List(Of Integer)
Return _list
End Function
End Class
Foo() writes:
321
123
So you can actually manipulate the backing field after you were supposedly done with it!
let take a simple example
there is not much information, i will assume GetMyList is a list(of integer)
Module Module1
Sub Main()
test1()
test2()
Console.ReadKey(False)
End Sub
Sub test1()
Dim list = SomeClass.GetMyList()
For Each item In list
Console.WriteLine(item)
Next
End Sub
Sub test2()
For Each item In SomeClass.GetMyList()
Console.WriteLine(item)
Next
End Sub
End Module
Class SomeClass
Public Shared Function GetMyList() As List(Of Integer)
Dim aList = New List(Of Integer)
aList.Add(1)
aList.Add(2)
aList.Add(3)
Console.WriteLine("I am in the function now")
Return aList
End Function
End Class
you can run it yourself to see the behavior
now let look at the actual IL (compiled with debug)
test1 code;
.method public static
void test1 () cil managed
{
// Method begins at RVA 0x2120
// Code size 64 (0x40)
.maxstack 1
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
[1] int32 item,
[2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> VB$t_struct$L0,
[3] bool VB$CG$t_bool$S0
)
IL_0000: nop
IL_0001: call class [mscorlib]System.Collections.Generic.List`1<int32> ConsoleApplication1.SomeClass::GetMyList()
IL_0006: stloc.0
IL_0007: nop
.try
{
IL_0008: ldloc.0
IL_0009: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000e: stloc.2
IL_000f: br.s IL_0021
// loop start (head: IL_0021)
IL_0011: ldloca.s VB$t_struct$L0
IL_0013: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0018: stloc.1
IL_0019: ldloc.1
IL_001a: call void [mscorlib]System.Console::WriteLine(int32)
IL_001f: nop
IL_0020: nop
IL_0021: ldloca.s VB$t_struct$L0
IL_0023: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0028: stloc.3
IL_0029: ldloc.3
IL_002a: brtrue.s IL_0011
// end loop
IL_002c: nop
IL_002d: leave.s IL_003e
} // end .try
finally
{
IL_002f: ldloca.s VB$t_struct$L0
IL_0031: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_0037: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003c: nop
IL_003d: endfinally
} // end handler
IL_003e: nop
IL_003f: ret
} // end of method Module1::test1
test2 code;
.method public static
void test2 () cil managed
{
// Method begins at RVA 0x217c
// Code size 62 (0x3e)
.maxstack 1
.locals init (
[0] int32 item,
[1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> VB$t_struct$L0,
[2] bool VB$CG$t_bool$S0
)
IL_0000: nop
IL_0001: nop
.try
{
IL_0002: call class [mscorlib]System.Collections.Generic.List`1<int32> ConsoleApplication1.SomeClass::GetMyList()
IL_0007: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000c: stloc.1
IL_000d: br.s IL_001f
// loop start (head: IL_001f)
IL_000f: ldloca.s VB$t_struct$L0
IL_0011: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: call void [mscorlib]System.Console::WriteLine(int32)
IL_001d: nop
IL_001e: nop
IL_001f: ldloca.s VB$t_struct$L0
IL_0021: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: brtrue.s IL_000f
// end loop
IL_002a: nop
IL_002b: leave.s IL_003c
} // end .try
finally
{
IL_002d: ldloca.s VB$t_struct$L0
IL_002f: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_0035: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003a: nop
IL_003b: endfinally
} // end handler
IL_003c: nop
IL_003d: ret
} // end of method Module1::test2
only thing different is when the GetMyList reference is called / loaded in memory
first one load it in a local variable, the second one just load it when the loop start
so both scenario will do the same thing.

Marshalling ref IntPtr to BSTR * in C#

I am trying to call a function which allocates memory for the string and then does something with the string. Here is the basic example which illustrates the problem:
C++:
STDMETHODIMP CFunctionsCollection::Function2 (
BSTR leftString, BSTR rightString, BSTR * conString
)
{
int leftLen = lstrlen(leftString);
int rightLen = lstrlen(rightString);
*conString = new TCHAR[leftLen+rightLen+1];
for (int i=0 ; i<leftLen ; ++i)
(*conString)[i] = leftString[i];
for (int i=0 ; i<rightLen ; ++i)
(*conString)[leftLen+i] = rightString[i];
(*conString)[leftLen+rightLen] = 0;
return S_OK;
}
The following call from C++ program works just fine:
BSTR leftString = SysAllocString(L"Left String");
BSTR rightString = SysAllocString(L"Right String");
BSTR conString;
hr = pFunctionsCollection->Function2 ( leftString, rightString, & conString);
C# declaration:
Int32 Function2([In, MarshalAs(UnmanagedType.BStr)] String leftString,
[In, MarshalAs(UnmanagedType.BStr)] String rightString,
[In, Out] ref IntPtr conStr);
C# call:
try
{
String leftString = "Left String";
String rightString = "Right String";
IntPtr outStr = IntPtr.Zero;
pFunctionsCollection.Function2(leftString, rightString, ref outStr);
String outString = Marshal.PtrToStringUni(outStr);
Console.WriteLine("Out String = {0}", outString);
}
catch (Exception e)
{
Console.WriteLine("Call to Function2 failed with {0}", e.Message);
}
The program fails with
Call to Function2 failed with Insufficient memory to continue the execution of the program.
Does anyone knows how to make such a calls from C#?
conString is a BSTR, and must be treated as such. See http://msdn.microsoft.com/en-us/library/ms221069.aspx
You should use SysStringLen to get the length of the BSTRs
You last parameter in C# should be an out string marshalled as a BSTR
[In, Out, MarshalAs(UnmanagedType.BStr)] out string conStr
You need to allocate the memory for conStr with SysAllocString or SysAllocStringLen
List item
You cannot allocate memory using 'new' and cast it to a BSTR. BSTR's have specific requirements for memory management and layout that you are not satisfying. You must follow these conventions always. The interop fails because it expects you are following the conventions for BSTRs, but you are not.

Or versus OrElse

What's the difference between or and OrElse?
if temp is dbnull.value or temp = 0
produces the error:
Operator '=' is not defined for type 'DBNull' and type 'Integer'.
while this one works like a charm!?
if temp is dbnull.value OrElse temp = 0
OrElse is a short-circuiting operator, Or is not.
By the definition of the boolean 'or' operator, if the first term is True then the whole is definitely true - so we don't need to evaluate the second term.
OrElse knows this, so doesn't try and evaluate temp = 0 once it's established that temp Is DBNull.Value
Or doesn't know this, and will always attempt to evaluate both terms. When temp Is DBNull.Value, it can't be compared to zero, so it falls over.
You should use... well, whichever one makes sense.
This is the same behaviour as with C#, where everyone uses the Coditional Or (||) and the Conditional And (&&), where you also have the normal Or (|) and normal And (&). So comparing C# to VB.Net is:
| => Or
|| => OrElse
& => And
&& => AndAlso
The condifitonal boolean operators are very usefull preventing nested if constructions. But sometimes the normal boolean operators are needed to ensure hitting both code paths.
OrElse is short circuited, this means that only one side of the expression will be tested if the first side is a match.
Just like AndAlso will only test one side of the expression if the first half is a fail.
OrElse evaluate first expression then if its true it will proceed to the statement while OR evaluates two expressions before it will proceed to their statement.
Example:
Textbox1.Text= 4
Textbox2.Text= ""
Using OrElse
If TextBox1.Text > 2 OrElse TextBox2.Text > 3 Then
MsgBox("True")
End If
Result is: TRUE
Using OR
If TextBox1.Text > 2 Or TextBox2.Text > 3 Then
MsgBox("True")
End If
Result is: Error cannot convert string to double.
(I've looked at other answers and realized I was terribly wrong)
The OrElse operator "performs short-circuiting logical disjunction on two expressions", that is to say: if the left operand is true and so the entire expression is guaranteed to be true the right operand won't even be evaluated (this is useful in cases like:
string a;
//...
if (a is null) or (a = "Hi") //...
to avoid a NullReferenceException throw by the right-hand operand.
I'm sincerely astonished that this (lazy evaluation) isn't the default behaviour of or and and as it is in C/C++ and C# (and many other languages...)
The Bert' s answer is not very accurate. The '|' or '&' is logical operator, in C #, it always treat as bit operator, please see the following code as example
static void Main()
{
object a = null;
int b = 3;
if (a == null | a.ToString() == "sdffd")
{
Console.WriteLine("dddd");
}
Console.WriteLine(b | b);
Console.Read();
}
The following is IL
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 62 (0x3e)
.maxstack 3
.locals init ([0] object a,
[1] int32 b,
[2] bool CS$4$0000)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldc.i4.3
IL_0004: stloc.1
IL_0005: ldloc.0
IL_0006: ldnull
IL_0007: ceq
IL_0009: ldloc.0
IL_000a: callvirt instance string [mscorlib]System.Object::ToString()
IL_000f: ldstr "sdffd"
IL_0014: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0019: or
IL_001a: ldc.i4.0
IL_001b: ceq
IL_001d: stloc.2
IL_001e: ldloc.2
IL_001f: brtrue.s IL_002e
IL_0021: nop
IL_0022: ldstr "dddd"
IL_0027: call void [mscorlib]System.Console::WriteLine(string)
IL_002c: nop
IL_002d: nop
IL_002e: ldloc.1
IL_002f: ldloc.1
IL_0030: or
IL_0031: call void [mscorlib]System.Console::WriteLine(int32)
IL_0036: nop
IL_0037: call int32 [mscorlib]System.Console::Read()
IL_003c: pop
IL_003d: ret
} // end of method Program::Main
when you use || to test "a == null" and "a.ToString() == "sdffd", the IL will be
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 63 (0x3f)
.maxstack 2
.locals init ([0] object a,
[1] int32 b,
[2] bool CS$4$0000)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldc.i4.3
IL_0004: stloc.1
IL_0005: ldloc.0
IL_0006: brfalse.s IL_001d
IL_0008: ldloc.0
IL_0009: callvirt instance string [mscorlib]System.Object::ToString()
IL_000e: ldstr "sdffd"
IL_0013: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0018: ldc.i4.0
IL_0019: ceq
IL_001b: br.s IL_001e
IL_001d: ldc.i4.0
IL_001e: stloc.2
IL_001f: ldloc.2
IL_0020: brtrue.s IL_002f
IL_0022: nop
IL_0023: ldstr "dddd"
IL_0028: call void [mscorlib]System.Console::WriteLine(string)
IL_002d: nop
IL_002e: nop
IL_002f: ldloc.1
IL_0030: ldloc.1
IL_0031: or
IL_0032: call void [mscorlib]System.Console::WriteLine(int32)
IL_0037: nop
IL_0038: call int32 [mscorlib]System.Console::Read()
IL_003d: pop
IL_003e: ret
} // end of method Program::Main
Now you can see the difference, please don't think the '|' or 'and' as conditional operator, it just a logical operator, I don't think there is necessary to use it to judge condition
The reason the compilation fails in the example is the order of operations.
The expression parser is trying to evaluate "dbnull.value or temp" first.
if temp is (dbnull.value or temp) = 0
The error is here, because you can't do a bitwise OR between an integer (temp) and dbnull.value.
OrElse fixes this, not because it's short-circuited, but because it's lower on the order of operations, and so "temp is dbnull.value" and "3=0" are being evaluated first, rather than the parser trying to compare dbNull and temp.
So the evaluation with OrElse works like you're expecting: (assume temp=3)
if temp is dbnull.value OrElse temp = 0 then
if 3 is dbnull.value OrElse 3 = 0 then
if false OrElse 3=0 then
if false OrElse false then
if false then
This was actually on an entry exam at a software company I used to work for, and it was a common problem I used to encounter in VB6. So it's a good idea to parenthesize your sub-expressions when using boolean operators:
This would have compiled properly:
if (temp is dbnull.value) Or (temp = 0) then
Although, as everyone has already pointed out, OrElse and AndAlso are really the correct operators to use in this context.
Unless your code logic requires the short-circuiting behavior OrElse provides, I would lean toward using the Or operator because:
Using "Or" is simple and requires less typing.
The computational time savings of using OrElse is negligible in most cases.
Most importantly, using OrElse can hide errors in later clauses that may not be initially revealed until those conditions would eventually be met by the program logic.

Why does Integer.TryParse set result to zero on failure?

My understanding of the Integer.TryParse() function was that it tried to parse an integer from the passed in string and if the parse failed the result integer would remain as it did before.
I have an integer with a default value of -1 which I would like to remain at -1 if the parse fails. However the Integer.TryParse() function on failing to parse is changing this default value to zero.
Dim defaultValue As Integer = -1
Dim parseSuccess As Boolean = Integer.TryParse("", defaultValue)
Debug.Print("defaultValue {0}", defaultValue)
Debug.Print("parseSuccess {0}", parseSuccess)
My expectation is that the code snippet above should output:
defaultValue -1
parseSuccess False
However instead it outputs:
defaultValue 0
parseSuccess False
Is my understanding correct?
It's an out parameter, which means it must be set by the method (unless it throws an exception) - the method can't see what the original value was.
The alternative would have been to make it a ref parameter and only set it on success, but that would mean forcing callers to initialize the variable first even if they didn't want this behaviour.
You can write your own utility method though:
public bool TryParseInt32(string text, ref int value)
{
int tmp;
if (int.TryParse(text, out tmp))
{
value = tmp;
return true;
}
else
{
return false; // Leave "value" as it was
}
}
You are correct, TryParse uses 0 if it fails. (MSDN says this quite clearly)
But you could check paseSuccess and return your default value if this is what you want to.