How to write a VB.Net Lambda expression - vb.net

I am working on a VB.net project now. I am new to VB.Net LINQ and would like to know the Lambda equivalent of
var _new = orders.Select(x => x.items > 0);
in VB.Net.
Someone please suggest!

The lambda syntax isn't that much different than creating a regular delegate.
If creating a lambda which has a return value, use Function. Otherwise if you're creating one that doesn't, use Sub.
Dim _new = orders.Select(Function(x) x.Items > 0)
Dim action As Action(Of Item) = Sub(x) Console.WriteLine(x.Items)

Related

VB.NET equivalent of Func

I have a C# statement
solidGauge1.LabelFormatter = val => val.ToString("P");
I want the VB.NET equivalent. Telerik code converter gives
"solidGauge1.LabelFormatter = Function(val) val.ToString("P")"
This is not correct since it seems to be ignored. The C# statment works in a C# project. The usage/source of this is lvCharts Gauge control
Try this
solidGauge1.LabelFormatter = Val.ToString("P")

Call instance method inline after New statement

How can i convert this code to VB.net
public void SetBooks(IEnumerable<Book> books)
{
if (books == null)
throw new ArgumentNullException("books");
new System.Xml.Linq.XDocument(books).Save(_filename);
}
in http://converter.telerik.com/ it says:
Public Sub SetBooks(books As IEnumerable(Of Book))
If books Is Nothing Then
Throw New ArgumentNullException("books")
End If
New System.Xml.Linq.XDocument(books).Save(_filename)
End Sub
But visual studio says "Syntax error." because of "New"
What is the keyword for this situation, i searched on Google but no result.
Actually, you can do it in one line with the Call keyword
Call (New System.Xml.Linq.XDocument(books)).Save(_filename)
You cannot initialize an object and use it in one statement in VB.NET (as opposed to C#). You need two:
Dim doc = New System.Xml.Linq.XDocument(books)
doc.Save(_filename)
In C# the constructor returns the instance of the created object, in VB.NET not.

Lambda and VB.NET

I have found this example on StackOverflow:
var people = new List<Person> {
new Person{Name="aaa", Salary=15000, isHip=false}
,new Person{Name="aaa", Salary=15000, isHip=false}
,new Person{Name="bbb", Salary=20000, isHip=false}
,new Person{Name="ccc", Salary=25000, isHip=false}
,new Person{Name="ddd", Salary=30000, isHip=false}
,new Person{Name="eee", Salary=35000, isHip=false}
};
people.Where(p => p.Salary < 25000).Update(p => p.isHip = true);
foreach (var p in people)
{
Console.WriteLine("{0} - {1}", p.Name, p.isHip);
}
public static void Update<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
In C# everything works fine.
I tried to convert it in VB.NET.
Here's the code:
<System.Runtime.CompilerServices.Extension()> _
Public Sub Update(Of T)(ByVal source As IEnumerable(Of T), ByVal action As Action(Of T))
For Each item In source
action(item)
Next item
End Sub
If I try to update my collection things don't work, though:
people.Where(Function(p) p.Salary < 25000).Update(Function(p) p.isHip = true)
I am using VS2008 (3.5)
This thing is driving me crazy.
Is there anybody who can help me?
Alberto
You should always post what exactly is not working.
In your case, you want to Update list elements, which works though passing an Action(Of T) that should be run for every element.
Such an action, that is just run, performs some side-effects but returns no value is described by exactly one VB construct: A Sub.
Thus what you would want to write is
.Update(Sub(p) p.isHip = true)
which is valid VB2010, but simply does not work in the 2008 version. C# doesn't have a problem there, but in your VB code, you want to pass a Function which has to produce a value and not just perform an assignment. Func(Of ...) would be the appropriate type of that expression.
So what to do?
You can't just express what you want in the syntax of your version. But probably you shouldn't - build a new collection without modifying an old one. Is soon as you're dealing with value types/properties, the above approch won't work at all, since actually a temporary collection returned by Where is modified. Linq is no modification language, but a query system.
Anyway: Just use a plain loop.

Is it possible to pass a variable's name along with the value, when passing through functions?

I want to know if it's possible to retrieve the variables name from when it was passed into a certain function. For example, if I call parseId(myId) to a function with the signature parseId(id), i can obviously retrieve the value of 'id'. However, is there any way I can retrieve 'myId' as a string (without passing it as another value)?
Specifically in vb.net, but I'm interested in how it would work in any given language.
This is all just random thoughts.. feel free to dismiss or not ;-p
Re your comment about use with stored procedures... if you want to go that route, I wouldn't mess around with the local variable names; that is an implementation detail. However, you could expose those details on an interface method and use the names from there, since that is more formalised - for example (C#):
interface ICustomerRepository {
Customer GetById(int id); // perhaps an attribute to name the sproc
}
You can use similar expression-tree parsing (as discussed here) to get the name and value of the parameter, for example:
var repoWrapper = new Repo<ICustomerRepository>();
int custId = 12345;
var cust = repoWrapper.Execute(r => r.GetById(custId));
Here we'd want to resolve the argument to GetById as "id" (not "custId"), with value 12345. This is actually exactly what my protobuf-net RPC code does ;-p (just don't ask me to translate it to VB - it is hard enough to write it in a language you know well...)
No, you can't do that in the normal sense. What are you really trying to accomplish with this?
You can do this in .NET 3.5 and above using expression trees; I'll knock up a C# example, and try to run it through reflector for VB...
C#:
static void Main()
{
int i = 17;
WriteLine(() => i);
}
static void WriteLine<T>(Expression<Func<T>> expression)
{
string name;
switch (expression.Body.NodeType)
{
case ExpressionType.MemberAccess:
name = ((MemberExpression)expression.Body).Member.Name;
break;
default:
throw new NotSupportedException("Give me a chance!");
}
T val = expression.Compile()();
Console.WriteLine(name + "=" + val);
}
The VB is below, but note that the VB compiler seems to use different names (like $VB$Local_i, not i):
Sub Main()
Dim i As Integer = 17
WriteLine(Function() i)
End Sub
Private Sub WriteLine(Of T)(ByVal expression As Expression(Of Func(Of T)))
If (expression.Body.NodeType <> ExpressionType.MemberAccess) Then
Throw New NotSupportedException("Give me a chance!")
End If
Console.WriteLine((DirectCast(expression.Body, MemberExpression).Member.Name
& "=" & Convert.ToString(expression.Compile.Invoke)))
End Sub

Iterator pattern in VB.NET (C# would use yield!) [duplicate]

This question already has answers here:
Yield in VB.NET
(8 answers)
Closed 9 years ago.
How do implement the iterator pattern in VB.NET, which does not have the yield keyword?
This is now supported in VS 2010 SP1, with the Async CTP, see: Iterators (C# and Visual Basic) on MSDN and download Visual Studio Async CTP (Version 3).
Code such as this, works:
Private Iterator Function SomeNumbers() As IEnumerable
' Use multiple yield statements.
Yield 3
Yield 5
Yield 8
End Function
VB.NET does not support the creation of custom iterators and thus has no equivalent to the C# yield keyword. However, you might want to look at the KB article How to make a Visual Basic .NET or Visual Basic 2005 class usable in a For Each statement for more information.
C#'s yield keyword forces the compiler to create a state machine in the background to support it. VB.Net does not have the yield keyword. But it does have a construct that would allow you to create a state machine within a function: Static function members.
It should be possible to mimic the effects of a yield return function by creating a generic class that implements IEnumerable as well as the needed state machine and placing an instance as a static member inside your function.
This would, of course, require implementing the class outside of the function. But if done properly the class should be re-usable in the general case. I haven't played with the idea enough to provide any implementation details, though.
Hmm, looks like you might be out of luck:
I was struggling with an issue today when converting some C# to VB.NET. C# has a really cool "yield return" statement that is used in an iterator block to provide a value to the enumerator object. VB.NET does not have the "yield" keyword. So, there are a few solutions (none of which are really clean) to get around this. You could use a return statement to return the value if you are looping through and would like to break an enumerator and return a single value. However, if you'd like to return the entire enumeration, create a List() of the child type and return the list. Since you are usually using this with an IEnumerable, the List() will work nice.
That was written a year ago, not sure if anyone has come up with anything else better since then..
Edit: this will be possible in the version 11 of VB.NET (the one after VS2010), support for iterators is planned. The spec is available here.
Keep in mind that deferred execution and lazy evaluation properties of LINQ expresssions and methods allow us to effectively implement custom iterators until the yield statement is available in .NET 4.5. Yield is used internally by LINQ expressions and methods.
The following code demonstrates this.
Private Sub AddOrRemoveUsersFromRoles(procName As String,
applicationId As Integer,
userNames As String(),
rolenames As String())
Dim sqldb As SqlDatabase = CType(db, SqlDatabase)
Dim command As DbCommand = sqldb.GetStoredProcCommand(procName)
Dim record As New SqlDataRecord({New SqlMetaData("value", SqlDbType.VarChar,200)})
Dim setRecord As Func(Of String, SqlDataRecord) =
Function(value As String)
record.SetString(0, value)
Return record
End Function
Dim userNameRecords As IEnumerable(Of SqlDataRecord) = userNames.Select(setRecord)
Dim roleNameRecords As IEnumerable(Of SqlDataRecord) = rolenames.Select(setRecord)
With sqldb
.AddInParameter(command, "userNames", SqlDbType.Structured, userNameRecords)
.AddInParameter(command, "roleNames", SqlDbType.Structured, roleNameRecords)
.AddInParameter(command, "applicationId", DbType.Int32, applicationId)
.AddInParameter(command, "currentUserName", DbType.String, GetUpdatingUserName)
.ExecuteNonQuery(command)
End With
End Sub
Below gives output: 2, 4, 8, 16, 32
In VB.NET
Public Shared Function setofNumbers() As Integer()
Dim counter As Integer = 0
Dim results As New List(Of Integer)
Dim result As Integer = 1
While counter < 5
result = result * 2
results.Add(result)
counter += 1
End While
Return results.ToArray()
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For Each i As Integer In setofNumbers()
MessageBox.Show(i)
Next
End Sub
In C#
private void Form1_Load(object sender, EventArgs e)
{
foreach (int i in setofNumbers())
{
MessageBox.Show(i.ToString());
}
}
public static IEnumerable<int> setofNumbers()
{
int counter=0;
//List<int> results = new List<int>();
int result=1;
while (counter < 5)
{
result = result * 2;
counter += 1;
yield return result;
}
}