I have the following code that works fine in VB.net ( VS 2012 ). Note that m.Listen is returning an IObservable(of Maybe(of NominalObject))
Dim d As IDisposable = (From x In m.Listen(Of Maybe(Of NominalObject))()
From y In x
Select New LAPViewCommands(y)).
BindToControl(Me, Function(x) x.ViewModel)
d.DisposeWith(Me)
This is part of a custom user control and I have some extension methods for
binding IObservables to models. However the details are irrelevant. When
I change the code to
(From x In m.Listen(Of Maybe(Of NominalObject))()
From y In x
Select New LAPViewCommands(y)).
BindToControl(Me, Function(x) x.ViewModel).
DisposeWith(Me)
I have a compile error. Note there is no problem with the fluent syntax.
m.
Listen(Of Maybe(Of NominalObject)).
SelectMany(Function(x) x.Select(Function(y) New LAPViewCommands(y))).
BindToControl(Me, Function(x) x.ViewModel).
DisposeWith(Me)
Is this problem a strange edge case of the VB.NET parser or is there something
important here I'm missing? In summary the question is. Why can't I bracket a
LINQ query expression and then use fluent extension methods that return void
The problem is that your expression doesn't start with an identifier.
It's a limitation of VB.Net and not limited to LINQ query expressions.
Compare the following C# code (Dump is an extension method)
"123".Dump();
(from a in "1223" select a).Dump();
new object().ToString();
which will work fine. Here's the VB.Net equivalent (which more or less looks the same):
"123".Dump()
(From a in "123" Select a).Dump()
(New Object()).ToString()
and each of the three statements will throw a syntax error.
You can fix it by using the Call statement:
Call "123".Dump()
Call (From a in "123" Select a).Dump()
Call New Object().ToString()
Related
I have a simple query:
dim res = (From x In db.INVENTORies
Where x.INVENTORY_ACTIVATION_DATE IsNot Nothing).count
I need to run this for 14 different date fields, so how do I run this where INVENTORY_ACTIVATION_DATE can be a variable/dynamic?
something like:
function GetCount(aField as string) as integer
return (From x In db.INVENTORies
Where x.**<Use aField here>** IsNot Nothing).count
end function
Thanks in advance.
Steve
I've tried Dynamic Linq and PredicateBuilder, but there are no good examples for my scenario.
C# Eval Expression
Disclaimer: I'm the owner of the project C# Eval Expression
The library is not free, but you can do pretty much any dynamic LINQ using the same syntax as C#.
So it can be used in your VB.NET application, but you will need to use C# syntax for the dynamic part
return context.Customers.WhereDynamic("x => x.AnyField != null && x.AnyField2 != null").count
As you can see, you simply need to create the string to execute dynamically.
LINQ Dynamic
https://www.nuget.org/packages/System.Linq.Dynamic.Core/
The same can be achieved with LINQ Dynamic. You can find some where example here
You don't have to use the PredicateBuilder but simply create the string dynamically.
Through much trail and error, I finally got this working. I ended up using System.Linq.Dynamic.Core.
In c# i can do:
_ = Bla();
Can I do that in VB.Net ?
I think the answer is no but I just wanted to make sure.
The underscore (_), as used in your example, is C#'s discard token. Unfortunately, there is (currently) nothing similar in VB. There is a discussion about adding a similar feature on the VB language design github page.
In your example, however, you can just omit assigning the result (both in C# and VB), i.e.
Bla(); // C#
Bla() ' VB
The "discard variable" is particularly useful for out parameters. In VB, you can just pass an arbitrary value instead of a variable to discard unused ByRef parameters. Let me give you an example:
The following two lines are invalid in C#:
var b = Int32.TryParse("3", 0); // won't compile
var b = Int32.TryParse("3", out 0); // won't compile
Starting with C# 7, you can use _ for that purpose:
var b = Int32.TryParse("3", out _); // compiles and discards the out parameter
This, however, is perfectly valid in VB, even with Option Strict On:
Dim b = Int32.TryParse("3", 0)
So, yes, it would be nice to make the fact that "I want to ignore the ByRef value" more explicit, but there is a simple workaround in VB.NET. Obviously, once VB.NET gets pattern matching or deconstructors, this workaround won't be enough.
The MongoDB C# driver supports queries on Nullable(Of T) according to this Jira ticket:
https://jira.mongodb.org/browse/CSHARP-483
However, I am having issues getting it working.
mycol.AsQueryable.Where(Function(p) p.MyNullableInteger = 3)
As instructed, I removed the .Value property from the query, however that breaks strict typing, so I had to remove my Option Strict On clause. It then compiled successfully however I would ideally like that clause back in.
The PredicateTranslator is throwing an exception as follows:
Unsupported where clause: (Boolean)(p.MyNullableInteger == (Nullable)3)
The actual Where clause expression generated by .NET is:
p => Convert((p.MyNullableInteger == ConvertChecked(3)))
I am using driver 1.5. My POCO class does register a classmap but the mapping does not reference the property here (it is just setting representation from String to ObjectId for my Id property).
Turns out this is only a bug in Visual Basic. It works fine in C#. I have created a Jira here: https://jira.mongodb.org/browse/CSHARP-542.
I'm also going to edit your question tags to include VB as opposed to c#.
I have a simple code in C#:
Console.WriteLine(string.Join<char>("", ""));
And I can't convert it to VB.Net. Even reflector show me code in VB like:
Console.WriteLine(String.Join(Of Char)("", ""))
But it can't be compiled becouse I have an starge error:
Error 1 Expression expected.
It looks like VB.Net don't have this generic method at all.
Both project use Net Framework 4.
Why this error happened?
UPD:
I've create a custom class and copy Join(Of T) declaration to it:
Class string2
Public Shared Function Join(Of T)(ByVal separator As String, ByVal values As System.Collections.Generic.IEnumerable(Of T)) As String
Return "1"
End Function
End Class
Console.WriteLine(string2.Join(Of Char)("", ""))
It works
UPD2:
My compilation string, where you can see that I'm using Net4:
http://pastebin.com/TYgS3Ys3
Do you have a code element named String somewhere in your project?
Based on the answer you have added to this question (where you indicate that changing String to [String] appears to have solved the problem), I guessed that this may be the result of a naming collision.
I was able to duplicate the error you are seeing -- "Expression expected" -- by adding a module to my project called String and defining a (non-generic) Join method from within that module.
This may not be the specific scenario you find yourself in. But the fact that the code works for you with [String] is, to me, very compelling evidence of a simple namespace collision.
Based on the documentation for the "Expression expected" error, I'm guessing you haven't included the entire section of code where this error is appearing for you.
Do you have a lingering operator such as + or = somewhere?
(The VB.NET code you posted is indeed equivalent to the C# code above it and should compile no problem. This is why I suspect the real issue lies elsewhere.)
String.Join<T>(string, IEnumerable<T>) is useful with LINQ, for standard joins is better to use the String.Join(string, string()) overload.
In C#, "" as Char produces an empty Char (\0). Writing the same thing ("") in VB produces an empty string which is not the same as an empty char. In order to produce an empty character, you'll have to write New Char().
Your VB code therefore becomes:
Console.WriteLine(String.Join(Of Char)(New Char(), New Char()))
Edit
I just checked and it appears String.Join does not support the format you're specifying.
Instead, it goes as follows:
Join(separator As String, value As String()) As String
Your code should be as follows:
Console.WriteLine(String.Join("", New String() {""}))
String.Join(Of Char)(str1, str2) wasn't added til .net 4, it seems. That's why your custom class worked -- it had the declaration, but the String class in the framework you're actually using doesn't.
Check your settings and references to make sure you're targeting .net 4 all around -- cause that's the only thing that seems able at this point to stop the call from working.
Here the solution:
Console.WriteLine([String].Join(Of Char)("", ""))
Why this problem occurs only with generic method? I wish I know...
Using VB.net, the following snippet gives the error below.
Dim _account = Account.Find(Function(x As Account) x.AccountName = txtFilterAccountName.Text)
or similarly if I do
.SingleOrDefault (Function(x As Account) x.AccountName = txtFilterAccountName.Text)
will both give the error "The method 'CompareString' is not supported". If I make the same call searching for an integer (ID field) it works fine.
.SingleOrDefault (Function(x As Account) x.Id = 12)
So integer matching is fine but strings don't work Is this a problem with the VB.net templates?
No this is not a problem with Vb.Net templates.
The problem is that you are not using a normal LINQ provider. Based on your tag (subsonic) I'm guessing you're using a LINQ to SQL query.
The problem is that under the hood, this is trying to turn your code into an expression tree which is then translated into an SQL like query. Your project settings are turning your string comparison into a call in the VB runtime. Specifically, Microsoft.VisualBasic.CompilerServices.Operators.CompareString.
The LINQ2SQL generater in question or VB compiler (can't remember where this check is done off the top of my head) does not understand how to translate this to an equivalent bit of SQL. Hence it generates an error. You need to use a string comparison function which is supported by LINQ2SQL.
EDIT Update
It looks like the CompareString operator should be supported in the Linq2SQL case. Does subsonic have a different provider which does not support this translation?
http://msdn.microsoft.com/en-us/library/bb399342.aspx
The problem is with SubSonic3's SQL generator and the expression tree generated from VB.NET.
VB.NET generates a different expression tree as noted by JaredPar and SubSonic3 doesn't account for it - see Issue 66.
I have implemented the fix as described but it has yet to merge into the main branch of SubSonic3.
BlackMael's fix has been committed:
http://github.com/subsonic/SubSonic-3.0/commit/d25c8a730a9971656e6d3c3d17ce9ca393655f50
The fix solved my issue which was similar to John Granade's above.
Thanks to all involved.