Call instance method inline after New statement - vb.net

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.

Related

NullReferenceException on dll

Here is my code I get the error on:
Imports ADFactory
Public Class Salary
Inherits Salary_Datalayer
Protected _AD As New ADFactory.ADFactory
Protected Sub Page_Load(...)Handles Me.Load
_user = "username"
sDealer = _AD.GetUserCompany(_user)
It states that Protected _AD As New ADFactory.ADFactory is the line throwing the exception. I've looked online and read and changed it several times, declared 'New', am I missing something simple?
PatFromCanada was correct, my ADFactory was the problem. I didn't properly initialize a connection string within the reference, thus always throwing a nullexception, which apparently, I run into quite often in my questions. Thanks PatFromCanada!

FakeItEasy VB.NET issues with parameters

Ok, I am trying to teach myself testing using a mock framework and I work in VB.NET, I am new to lambda expressions and all my previous applications were written in version 2005 or earlier. I now have 2010.
So I have tried Rhino.Mocks but found it difficult to get my head around it mostly because of the older syntax. Since, no-one seems to be bloggin in VB.NET these days, I have been looking at C# examples and trying to figure out what is going on.
So I have a situation where I pass an interface to the constructor of a class and hold a refrence to that interface. When an method is called on the object and event is raise that should be handled by the class that implements the inteface.
I was having trouble, so I tried to create a simple version in C# and repeat the steps in vb.net.
So my interface:
public interface IBroadcastClient
{
void MessageReceivedHandler(string msg);
}
The class that raises the events:
public class Broadcaster
{
public Broadcaster(IBroadcastClient c)
{
_client= c;
this.SendMessage += new MessageReceived(_client.MessageReceivedHandler);
}
private IBroadcastClient _client;
public event MessageReceived SendMessage;
public void SendMessageNow()
{
string _Message;
if (SendMessage != null)
{
_Message = #"Yay!";
SendMessage(_Message);
}
}
}
The test:
[TestMethod]
public void TestSendMessageWithIgnoreParameter()
{
//string msg = #"Yay!";
var client = A.Fake<IBroadcastClient>();
Broadcaster b = new Broadcaster(client);
b.SendMessageNow();
A.CallTo(() => client.MessageReceivedHandler(A<string>.Ignored)).MustHaveHappened();
}
This passes, no problems so far.
Now to try the same this in vb.net;
The same interface and broadcaster class, just in vb.net rather than C# with initially hte following unit test.
<TestMethod()>
Public Sub TestMethod1()
Dim client = A.Fake(Of IBroadcastClient)()
Dim b As New Broadcaster(client)
b.SendMessageNow()
NextCall.To(client).MustHaveHappened()
client.MessageReceivedHandler(A(Of String).Ignored)
End Sub
This fails with the following error message;
" Assertion failed for the following call:
TestFakeItEasyVB.IBroadcastClient.MessageReceivedHandler(msg: )
Expected to find it at least once but found it #0 times among the calls:
1: TestFakeItEasyVB.IBroadcastClient.MessageReceivedHandler(msg: "Yay!")"
Funnily enough writing it this way;
<TestMethod()>
Public Sub TestMethod3()
Dim client = A.Fake(Of IBroadcastClient)()
Dim b As New Broadcaster(client)
b.SendMessageNow()
A.CallTo(Sub() client.MessageReceivedHandler(A(Of String).Ignored)).MustNotHaveHappened()
End Sub
Will also fail with the same error message, however, this version of the test passes.
<TestMethod()>
Public Sub TestMethod2()
Dim client = A.Fake(Of IBroadcastClient)()
Dim b As New Broadcaster(client)
b.SendMessageNow()
NextCall.To(client).MustHaveHappened()
client.MessageReceivedHandler("Yay!")
End Sub
This variation also passes in C#, my quandry is what am I doing wrong to get the test to ignore the argument passed to the faked event handler?
The NextCall-syntax is there for legacy reasons, it's better to use the expression syntax:
A.CallTo(Sub() client.MessageReceivedHandler(A(Of String).Ignored)).MustNotHaveHappened()
In your tests above all others has MustHaveHappened, but this specific one has MustNotHaveHappened, I guess that's why your test is failing. I've compiled your code and run it and once it's changed to MustHaveHappened the test passes.
Currently you can not use argument constraints in the VB-specific "NextCall"-syntax. However you can use the method "WhenArgumentsMatch" to rewrite your first test like this:
<TestMethod()>
Public Sub TestMethod1()
Dim client = A.Fake(Of IBroadcastClient)()
Dim b As New Broadcaster(client)
b.SendMessageNow()
NextCall.To(client).WhenArgumentsMatch(Function(a) a.Get(Of String)(0) = "Yay!").MustHaveHappened()
client.MessageReceivedHandler(Nothing)
End Sub
Or you could use the extension "WithAnyArguments" to ignore all arguments:
<TestMethod()>
Public Sub TestMethod1()
Dim client = A.Fake(Of IBroadcastClient)()
Dim b As New Broadcaster(client)
b.SendMessageNow()
NextCall.To(client).WithAnyArguments().MustHaveHappened()
client.MessageReceivedHandler(Nothing)
End Sub

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;
}
}