What is the VB.NET equivalent to this C# code? - vb.net

VB.NET equivalent to this C# code?
ctx.Load(site,
x => x.Lists.Where(l => l.Title != null));
I've tried
ctx.Load(site, Function(x) x.Lists.Where(Function(l) l.Title IsNot Nothing))
but this errors with "The expression (Convert(l.Title) != null) is not supported."
Thoughts

if Title is string try use IsNullOrEmpty();
or
Nullable(Of T).HasValue if Title is Nullable
or
Sub Main()
Dim list As New List(Of A)
Dim a1 As New A
a1.Title = "sqws"
Dim a2 As New A
a2.Title = Nothing
list.Add(a1)
list.Add(a2)
Dim q = From c In list Where c.Title IsNot Nothing
End Sub
Public Class A
Dim t As String
Public Property Title() As String
Get
Title = t
End Get
Set(ByVal value As String)
t = value
End Set
End Property
End Class

This may be cheating, but I have used Reflector in the past to decompile my C# code and then display it as other .NET languages just to see how they would look as I am most fluent in C#

This really should work:
ctx.Load(site, Function(x) x.Lists.Where(Function(l) l.Title.IsNullOrEmpty = False))
If it does not, let me know the error message.

Have you tried the IsNothing function?
ctx.Load(site, Function(x) x.Lists.Where(Function(l) Not IsNothing(l.Title)))
EDIT:
Now that you've specified that Title is a String, then you should use the IsNullOrEmpty function.
ctx.Load(site, Function(x) x.Lists.Where(Function(l) Not String.IsNullOrEmpty(l.Title)))

Related

Public member 'ToCSVValue' on type 'Integer' not found for VB Extension method

I am trying to write a ToCSV() extension in VB based on Scott Hanselman's blog. It could be that my C# to VB is not correct, but it all seems right.
I added a module with:
<System.Runtime.CompilerServices.Extension>
Public Function ToCSV(Of T)(items As IEnumerable(Of T)) As String
Try
Dim csvBuilder = New StringBuilder()
Dim properties = GetType(T).GetProperties()
For Each item As T In items
'' Test Code
Dim newline As String = ""
For Each l2 As Reflection.PropertyInfo In properties
' This works
newline &= l2.GetValue(item, Nothing)
' This works too
Dim int As Integer = 1234
Dim s As String = int.ToCSVValue()
'This works
Dim nl = l2.GetValue(item, Nothing)
' This blows up with "Public member 'ToCSVValue' on type 'Integer' not found."
' The Debugger type shows "Object {Integer}" which I assume to mean that the debugger interprets the object as an integer.
nl = nl.ToCSVValue()
Next
' Original code
Dim line As String = String.Join(",", properties.Select(Function(p) p.GetValue(item, Nothing).ToCSVValue()).ToArray())
csvBuilder.AppendLine(line)
Next
Return csvBuilder.ToString()
Catch ex As Exception
Throw
End Try
End Function
<System.Runtime.CompilerServices.Extension>
Private Function ToCSVValue(Of T)(item As T) As String
If item Is Nothing Then
Return """"""
End If
If TypeOf item Is String Then
Return String.Format("""{0}""", item.ToString().Replace("""", "\"""))
End If
Dim dummy As Double
If Double.TryParse(item.ToString(), dummy) Then
Return String.Format("{0}", item)
End If
Return String.Format("""{0}""", item)
End Function
When I call it with something like:
Dim s As String = ctx.Customers.Where(Function(x) x.CustomerID = 123456).Select(Function(x) New With {.CustomerID = x.CustomerID, .CustomerName = x.CustomerName}).ToCSV()
it gets to the function ToCSV just fine. It recognizes the items passed in. It pulls out the first item and sees that there are the 2 fields in it. All good!
The GetValue() works just fine.
If I create a static integer and call ToCSVValue on it, it works fine.
If I create a static string and call ToCSVValue on it, it works fine.
When I call ToCSVValue on the GetValue() I get:
Public member 'ToCSVValue' on type 'Integer' not found.
Likewise, if I have just strings in the dataset, I get:
Public member 'ToCSVValue' on type 'String' not found.
Ideally this would work as it is in the "Original code" section and I can kill all this other test code.
Can anyone tell me what is happening and why the "(Of T)" is not working the get GetValue() types, but it is for the directly cast types?
You need to have 'Option Infer On'.
When I use Option Infer On, it works fine.
If you don't use this, then VB is using 'Object' whenever you leave off the type.
Also, although this isn't causing your problem, the proper conversion of the ToCSV method is:
Public Function ToCSV(Of T As Class)(items As IEnumerable(Of T)) As String
The short answer is that calling it as a method ToCSVValue(p.GetValue(item, Nothing)) will work as in the C# version.
The longer answer is that you can't call extension methods on Object in VB. In VB Object is treated more like dynamic in C#. For example:
<Extension()> Function toStr(Of T)(item As T) As String
Return item.ToString
End Function
then this will result in compile-time Warning "Late bound resolution; runtime errors could occur." and a run-time Error "Public member 'toStr' on type 'Integer' not found.", but it will work in C#:
Dim i As Object = 123
Dim s = i.toStr

Setting Values Using Reflection

I am using VB.NET. I have created a small scale test project that works similar to my program. I am trying to say something like: getObjectType(object1) if Object1.getType() = "ThisType" then get the properties. Each object contains an ID and I would like to do this: Object1.Id = -1 (I know it won't be that short or easy). I thought there was a way to do this by using something like: Object1.SetValue(Value2Change, NewValue) but that doesn't work and I'm not sure how to exactly do this. Below is my code. Thank You!
Module Module1
Sub Main()
Dim Db As New Luk_StackUp_ProgramEntities
Dim Obj1 As IEnumerable(Of Stackup) = (From a In Db.Stackups).ToList
Dim Obj2 As IEnumerable(Of Object) = (From a In Db.Stackups).ToList
Dim IdNow As Integer = Obj1(0).IdStackup
Dim StackUpNow As Stackup = (From a In Db.Stackups Where a.IdStackup = IdNow).Single
Console.WriteLine(StackUpNow)
getInfo(StackUpNow)
getInfo(Obj1(0), Obj1(0))
areObjectsSame(Obj1(0), Obj1(67))
switchObjects(Obj1(0), Obj2(1))
getObjectValues(Obj2(55))
Console.WriteLine("========================================")
TestCopyObject(StackUpNow)
ChangeObjectValues(StackUpNow)
Console.ReadKey()
End Sub
Private Sub ChangeObjectValues(Object1 As Object)
Console.WriteLine("Changing Object Values")
Dim myField As PropertyInfo() = Object1.GetType().GetProperties()
'Dim Index As Integer 'Did not find value
'For Index = 0 To myField.Length - 1
' If myField(Index).ToString.Trim = "IdStackup" Then
' Console.WriteLine("Found the ID")
' End If
'Next
If Object1.GetType().Name = "Stackup" Then
'Set the Value
End If
End Sub
You can use PropertyInfo.SetValue to set the value using reflection. You could also use a LINQ SingleOrDefault query to simplify finding the correct PropertyInfo, so you could do something like this:
Private Sub ChangeObjectValues(Object1 As Object)
Console.WriteLine("Changing Object Values")
Dim t As Type = Object1.GetType()
If t.Name = "Stackup" Then
Dim myField As PropertyInfo = t.GetProperties() _
.SingleOrDefault(Function(x) x.Name = "IdStackup")
If myField IsNot Nothing Then
Console.WriteLine("Found the ID")
myField.SetValue(Object1, -1)
End If
End If
End Sub
It's not clear from the question if you really need to use reflection - perhaps a common interface to define the id property, or just type checking and casting, etc. would be better.
Well, I struggled to see how your code example applied to your question, but if you are simply asking how to set the ID of an object using reflection, this code might help you. The trick is that a property is typically handled using a set and a get method.
Imports System.Web.UI.WebControls
Imports System.Reflection
Module Module1
Sub Main()
Dim tb As New Label()
Dim t As Type = tb.GetType()
If TypeOf tb Is Label Then
Dim mi As MethodInfo = t.GetMethod("set_ID")
mi.Invoke(tb, New Object() {"-1"})
End If
Console.WriteLine(tb.ID)
Console.ReadLine()
End Sub
End Module

Make VB code that replaces LINQ expressions

I found this code on another answered question C# - How to xml deserialize object itself?
I really like this code and want to use it in my application but I target the .net 2.0 Compact framework, so I cant use the LINQ expressions. Is there anyone who can tell me how I can convert this into "Normal VB" code?
Original code from from user wheelibin.
I went for this approach:
Public Class SerialisableClass
Public Sub SaveToXML(ByVal outputFilename As String)
Dim xmls = New System.Xml.Serialization.XmlSerializer(Me.GetType)
Using sw = New IO.StreamWriter(outputFilename)
xmls.Serialize(sw, Me)
End Using
End Sub
Private tempState As Object = Me
Public Sub ReadFromXML(ByVal inputFilename As String)
Dim xmls = New System.Xml.Serialization.XmlSerializer(Me.GetType)
Using sr As New IO.StreamReader(inputFilename)
tempState = xmls.Deserialize(sr)
End Using
For Each pi In tempState.GetType.GetProperties()
Dim name = pi.Name
' THIS IS THE PART THAT i CANT FIGURE OUT (HOW TO DO THIS WITHOUT LINQ)
Dim realProp = (From p In Me.GetType.GetProperties
Where p.Name = name And p.MemberType = Reflection.MemberTypes.Property).Take(1)(0)
' -------------------------------------------------------------
realProp.SetValue(Me, pi.GetValue(tempState, Nothing), Nothing)
Next
End Sub
End Class
You can replace that LINQ part with "normal" For Each loop, for example :
Dim realProp As PropertyInfo
For Each p As PropertyInfo In Me.GetType.GetProperties()
If p.Name = Name And p.MemberType = Reflection.MemberTypes.Property Then
'set `realProp` with the first `p` that fulfil above `If` criteria'
'this is equivalent to what your LINQ (...).Take(1)(0) does'
realProp = p
Exit For
End If
Next

Using Moq's VerifySet in VB.NET

I have a function that updates a user in the asp.net membership provider.
<AcceptVerbs(HttpVerbs.Post)>
Public Function EnableUser(ByVal id As String) As JsonResult
Dim usr As StargatePortalUser = _membershipService.GetUser(id, Nothing)
usr.IsApproved = True
_membershipService.UpdateUser(usr)
Dim response As New AjaxResponse(usr.UserName)
Return Json(response)
End Function
I am trying to test this function to ensure the IsApproved property is set correctly
<TestMethod()>
Public Sub Service_Can_Enable_A_User_Account()
' Arrange
Dim usr As New Mock(Of MembershipUser)
usr.SetupProperty(Function(u) u.IsApproved)
_membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usr.Object)
Dim target As New UsersController(_membershipService.Object)
target.ControllerContext = New ControllerContext(FakeAuthenticatedHttpContext("testuser", String.Empty, True, True, False), New RouteData, target)
' Act
Dim actual As JsonResult = target.EnableUser("userId")
' Assert
Assert.IsTrue(DirectCast(actual.Data, AjaxResponse).Success)
_membershipService.Verify(Sub(m) m.UpdateUser(It.IsAny(Of MembershipUser)), Times.Once)
usr.Verify(Function(u) u.IsApproved = True)
End Sub
When I try to verify that the IsApproved property has been set to True an exception is returned:
System.ArgumentException: Expression is not a method invocation: u => (u.IsApproved == True)
There are so few examples of using Moq in VB that I can't figure this out, any help would be appreciated.
This is an ASP.NET MVC2 app in VB.NET 10 (.NET 4.0)
EDIT:
Ok, turns out it's not quite so straight forward in VB.
usr.Verify(Function(u) u.IsApproved = True)
needs to be
usr.VerifySet(Function(u) InlineAssignHelper(u.IsApproved, True))
and you need to add the following function:
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function
FURTHER EDIT:
Thinking around the problem I arrived at a more simple solution. I changed
Dim usr As New Mock(Of MembershipUser)
usr.SetupProperty(Function(u) u.IsApproved)
_membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usr.Object)
for
Dim usr As New Mock(Of MembershipUser)
usr.SetupProperty(Function(u) u.IsApproved)
Dim usrObj = usr.Object
_membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usrObj)
and then can replace
usr.VerifySet(Function(u) InlineAssignHelper(u.IsApproved, True))
with the more straightforward
Assert.IsTrue(usrOb.IsApproved)
Sometimes I just don't see the simple solution :)
You want to use the following (from http://code.google.com/p/moq/wiki/QuickStart):
// or verify the setter directly
mock.VerifySet(foo => foo.Name = "foo");
Right now the thing that you're feeding in is a comparison rather than an assignment, so even if Moq did process the statement without an exception, it would still not be Doing What You Mean.
Well this may be a little late, but I was facing the same problem and the solution was way simpler then using a InlineAssignHelper method.
Just change the Function to a Sub and it should work.
So try this instead:
usr.VerifySet(Sub(u) u.IsApproved = True)

VB.NET Generic Function

What I want to do is, based on the type of T do different opperations. Below is a simple example of my problem.
Public Shared Function Example(Of T)() As T
Dim retval As T
If TypeOf retval Is String Then
Dim myString As String = "Hello"
retval = myString
ElseIf TypeOf retval Is Integer Then
Dim myInt As Integer = 101
retval = myInt
End If
Return retval
End Function
I get the error "Value of Type 'String' Cannot be converted to 'T'" Same with the integer part. If I cast either to an object before asigning them to retval it works but I think that would defeat my purpose and be less efficient. Any Ideas? Thanks!
It's probably a bit late, but try this:
Public Shared Function CAnyType(Of T)(ByRef UTO As Object) As T
Return CType(UTO, T)
End Function
Public Shared Function ExecuteSQLstmtScalar(Of T)(ByVal strSQL As String) As T
Dim T_ReturnValue As T
' Here we have the result of a DB query '
Dim obj As Object = "Value from DB query cmd.ExecuteScalar"
Dim strReturnValue As Object = obj.ToString();
Try
Dim tReturnType As Type = GetType(T)
If tReturnType Is GetType(String) Then
Return CAnyType(Of T)(strReturnValue)
ElseIf tReturnType Is GetType(Boolean) Then
Dim bReturnValue As Boolean = Boolean.Parse(strReturnValue)
Return CAnyType(Of T)(bReturnValue)
ElseIf tReturnType Is GetType(Integer) Then
Dim iReturnValue As Integer = Integer.Parse(strReturnValue)
Return CAnyType(Of T)(iReturnValue)
ElseIf tReturnType Is GetType(Long) Then
Dim lngReturnValue As Long = Long.Parse(strReturnValue)
Return CAnyType(Of T)(lngReturnValue)
Else
MsgBox("ExecuteSQLstmtScalar(Of T): This type is not yet defined.")
End If
Catch ex As Exception
End Try
Return Nothing
End Function
(the secrect is casting your generic result to object, then casting from type Object to template type T).
PS:
You are responsible to ensure that your code works correctly with nullable types and NOT nullable types, as well as System.DbNull.Value. For example when string is NULL and return value type is Boolean (not nullable). On a sidenote, please also note that VB Nothing is NOT equal NULL, it's equal to C#'s default(T) (e.g. System.Guid.Empty for Guid)
With a generic method, T will be of exactly one type each time. Let's say that you have code calling Example(Of Integer). Now, in your mind, replace T with Integer. The resulting method will contain these lines (amongst others).
Dim retval As Integer
If TypeOf retval Is String Then
Dim myString As String = "Hello"
retval = myString
' more code follows '
Assigning a String to an integer like that will never work. Sure, that code will also never execute, since the If-block prevents that, but the code will still not compile. (As a side not, the above code will fail to compile because the TypeOf keyword is restricted to use with reference types, but that is another story)
Typically when creating generic methods, you will want to do the same thing with whatever input you get, but in a type safe manner. If you want to have different behavior for different types of input, you are usually better off by overloading the methods instead.
retVal = (T) "Hello World!"
Do retval = Ctype(Mystring, T) or retVal = Ctype(MyInt, T)
An alternative solution is encapsulate this kind of logic in a class and use VB CallByName function:
Class Aux(Of T)
Public Value As T
Private dicc As Dictionary(Of String, Object)
Sub New()
dicc = New Dictionary(Of String, Object)
dicc.Add("system.string", "hola")
dicc.Add("system.int32", 15)
dicc.Add("system.double", 15.0)
End Sub
Public Function Test() As T
Dim typeName As String = GetType(T).ToString.ToLower
If dicc.ContainsKey(typeName) Then
CallByName(Me, "Value", CallType.Set, dicc(typeName))
End If
Return Value
End Function
Protected Overrides Sub Finalize()
MyBase.Finalize()
If Not (dicc Is Nothing) Then dicc.Clear()
dicc = Nothing
End Sub
End Class