While maintaining a piece of VB.NET code from 2012, I came across a commented line containing what seems to be VB code (in a single line, without any explanation):
GetType(<PrivateImplementationDetails>).GetField("$$method0x6000001-7362C34F3136BD47ED8AEFEEF3833D69BFFC1F83").FieldHandle
What is <PrivateImplementationDetails>? Is this valid syntax (the syntax debugger breaks on the first <)? And if so, what is its purpose?
You can refer to Roslyn which says:
The main purpose of this class so far is to contain mapped fields and
their types.
Related
We are writing a tool in Java that parses and transforms ABAP code. We therefore have no intention to write new ABAP code but our tool has to handle all of ABAP, even obsolete statements. Furthermore, I'm not an ABAP expert.
ABAP programs can use type groups, introduced by key word TYPE-POOL. Names of type groups have a maximal length of five (internally eight, if you count the prefix "% C"), their type code is TYPP. In the past, relying on these assumptions worked well for us.
Recently, we see ABAP programs with type code TYPP but with name longer than 5, e.g., 'OIA===========================P'. Furthermore, for each of those, there is another, empty object with same name but type code INCL. These new objects are referenced only if a regular type group is, too.
These new objects may be internal ones and irrelevant for us - I haven't seen any reference to them in the ABAP Keyword Documentation. On the other hand, they are confusing us because we see them.
Can someone explain to me the meaning of these objects and point me to some documentation?
Edit: Here examples from an EHP7 for SAP ERP 6.0 system
An example object. Entries in D010INC look fine:
The same object now using type pool mrm. Where do the additional includes come from?
These objects are introduced through inclusions, extensions and switched objects. To read along:
Check type pool MRM, type mrm_idoc_data_ers - that type contains a statement to include rmrm_idoc_data_ers_sbo. A similar include statement pulls rmrm_upd_arseg_nfm into mrm_upd_arseg. That explains the last two lines. Your parser should have caught that.
RMRM_IDOC_DATA_ERS_SBO contains an enhancement point named RMRM_IDOC_DATA_ERS_SBO_02 that belongs to an enhancement spot ES_RMRM_IDOC_DATA_ERS_SBO. Similarly, RMRM_UPD_ARSEG_NFM contains an enhancement point RMRM_UPD_ARSEG_NFM_01 that belongs to the enhancement spot ES_RMRM_UPD_ARSEG_NFM.
For ES_RMRM_IDOC_DATA_ERS_SBO, an enhancement implementation named ISAUTO_MRM_RMRM_IDOC_DATA_ERS exists. For ES_RMRM_UPD_ARSEG_NFM, an implementation named /NFM/MM_RMRM_UPD_ARSEG_NFM exists. That explains the references ending with =E
The implementation ISAUTO_MRM_RMRM_IDOC_DATA_ERS is located in the package ISAUTO_MRM. The implementation /NFM/MM_RMRM_UPD_ARSEG_NFM is located in the package /NFM/MM. That explains the references ending with =P. Obviously, these references are not generated for every package:
The package ISAUTO_MRM is controlled by the switch AM_ERS, the package /NFM/MM is controlled by the switch /NFM/MM. That explains the references ending in =S.
Ultimately, these references can be used to determine which programs need to be re-generated when the state of a switch is changed.
Does anyone know how to put the enableCors into the controller on vb.net. i am working along with a pluralsight course and tried a code translator with no luck. my attempt is below.
<EnableCors(origins: "http://localhost:53080", headers: "*", methods: "*")>
The correct syntax would be something like this:
<EnableCors("http://localhost:53080", "*","*")>
The C# example appears to use named parameters. VB.NET supports that too, however the EnableCorsAttributes has properties and contractor arguments that only differ by letter casing. This confuses the compiler as to whether you are attempting to set the named parameter or the property in the attribute. So, in this case we can just drop the named arguments all together.
In Vb.net this <EnableCors("http://localhost:53080", "*","*")> will work, but, you have to add on NuGet the Microsoft.AspNet.WebApi.Cors and Microsoft.AspNet.Cors. You need to add Imports System.Web.Http.Cors on the class.
Remove any empty line between the http://localhost:53080", "*","*")> and the declaration of the controller class.
Question
How can I rewrite the below Moq tests so they work again in Roslyn? Obviously I could remove the Lambda, but I was hoping to avoid that.
Also, for interest sake: did the Roslyn compiler fix a bug that allowed these invalid statements to work previously or is this a compiler bug that now breaks these statements?
Details
I'm trying to move my mostly VB.NET solution to Visual Studio 2015, from Visual Studio 2013. All projects in the solution are targeting .NET 4.5. I am currently using Moq 4.0 for these tests. I have several Moq based Lambda unit tests that fail to compile in Visual Studio 2015, but compile and run fine in Visual Studio 2013. These tests have worked in Visual Studio 2010 and Visual Studio 2012 as well.
Most of the tests are very simple and look something like this:
Private _view As Mock(Of Views.ICreateSecurityUserView)
<Test>
Public Sub ValidateSave_CallWithBlankLogin_SetsViewToolError()
_view = New Mock(Of Views.ICreateSecurityUserView)()
_view.SetupGet(Of String)(Function(x) x.Login).Returns("")
_view.SetupGet(Of String)(Function(x) x.LoginName).Returns(loginNameValue)
_subject.ValidateSave()
_view.Verify(Sub(x) x.LoginFieldError = It.Is(Of String)(Function(s) Not String.IsNullOrEmpty(s)), Times.Once)
End Sub
The offending line will be this one: _view.Verify(Sub(x) x.LoginFieldError = It.Is(Of String)(Function(s) Not String.IsNullOrEmpty(s)), Times.Once)
The build error I get (as in the title) is:
Error BC36534 Expression cannot be converted into an expression tree.
I've fiddled with the expression a bit, seeing if the compiler would be happier if it was multi-line:
_view.Verify(Sub(x)
x.LoginFieldError = It.Is(Of String)(Function(s)
Return Not String.IsNullOrEmpty(s)
End Function)
End Sub, Times.Once)
But to no avail, since this just adds these extra errors (the Visual Studio 2013 compiler also doesn't like the multi-line version):
Error BC36675 Statement lambdas cannot be converted to expression trees.
Bad "Solution"
I am able to get this compiling if I change the test line to:
_view.Verify(Sub(x) VerifyFunctionNameError(x), Times.Once)
Which then calls the new, pointless, function:
Private Sub VerifyFunctionNameError(x As Views.ICreateSecurityFunctionView)
x.FunctionNameError = It.Is(Of String)(Function(s) Not String.IsNullOrEmpty(s))
End Sub
Your question is hard to answer, I can't get a decent repro for this without knowing the declarations. Nevertheless, there is certainly a hint why this should not compile from the VB.NET Language Specification. Find a copy of it on your machine in C:\Program Files (x86)\Microsoft Visual Studio 14.0\VB\Specifications\1033\Visual Basic Language Specification.docx
Navigate to chapter 11.1.1 and scroll down a bit to arrive at the Annotation block. I'll quote the most relevant part:
The exact translation between lambda methods and expression trees may not be fixed between versions of the compiler and is beyond the scope of this specification. For Microsoft Visual Basic 11.0, all lambda expressions may be converted to expression trees subject to the following restrictions:
1. Only single-line lambda expressions without ByRef parameters may be converted to expression trees. Of the single-line Sub lambdas, only invocation statements may be converted to expression trees.
First noteworthy detail is that Microsoft does not want to nail down the exact rules and that the specification is dated. Why they didn't want to nail is fairly visible, the restrictions are quite crippling and they would have wanted to leave room for improvement.
It does otherwise state explicitly why neither compiler version can convert your multi-line lambda method, only single-line is supported. Next part of the sentence explains why you can't make it work on VS2015, you are using an assignment statement and not a method invocation.
So this strongly hints that VS2013 was at fault, it should not have accepted your lambda method. It is a given that the very drastic Roslyn parser rewrite would tighten-up the syntax rules and avoid replicating bugs in previous versions. Also plenty of room to worry that the VS2013 code did not actually work correctly. Non-zero odds that it incorrectly parsed the lambda as an expression instead of a statement. In other words, getting a comparison expression instead of an assignment statement. VB.NET does open the door to this kind of ambiguity, the = operator is used both in expressions and assignment statements. This is a guess I cannot verify without a repro.
Best to bounce this off the guys that actually wrote the compiler. You can file a feedback report at connect.microsoft.com. Be sure to include a minimum repro that they can compile or they'll quickly give up. Beware that there are good odds that they will close it as "By design". That's what it looks like.
My above "Bad Solution" in my question, doesn't actually even work anyway. This fails when the test runs because it obviously can't determine anything from the sub.
The actual answer to my question is to use Mock.VerifySet, instead of Mock.Verify. We are actually doing this in most places, so I'm not sure why we used the other method here. A rewritten test that will work in 2013 and 2015 will look like this:
_view.VerifySet(Sub(x) x.LoginFieldError = It.Is(Of String)(Function(s) Not String.IsNullOrEmpty(s)), Times.Once)
This compiles and the tests are passing as well.
I was poking around in the Moq source code today and the reason for the different result is seen below:
Verify
public void Verify(Expression<Action<T>> expression, Times times)
{
Mock.Verify(this, expression, times, null);
}
VerifySet
public void VerifySet(Action<T> setterExpression, Times times)
{
Mock.VerifySet(this, setterExpression, times, null);
}
The Expression<Action<T>> has apparently had its handling changed, while the Action<T> doesn't appear to have had its changed.
This is at least a documentation error, if not a bug.
In VB.NET prior to .NET 4.0 (i.e. VB.NET 7 through 9) an empty Structure declaration fails at compile-time with
error BC30281: Structure 'MySimpleEmpty' must contain at least one instance member variable or Event declaration.
E.g. The following two structures compile successfully in VB10, and not prior:
Structure MySimpleEmpty
End Structure
Public Structure AnotherEmpty
Public Const StillEmpty As Boolean = True
End Structure
I note the documentation for the Error BC30281 stops at VB9, but the documentation for the Structure statement still has the datamemberdeclarations as required even as of VB11 (.NET 4.5 VS2012).
These two Structures compile in VB11 (VS2012) as well. (Thanks John Woo.)
Is there some blog entry or documentation confirming this is an intended change or a bug in VB10 and later?
Microsoft have marked this as a fixed bug, without actually stating what was fixed.
The VB11 (VS2012) documentation now says the datamemberdeclarations are optional in the grammar, but in the Parts table it says "Required. Zero or more..."!
I guess that's a fix... The VB10 (VS2010) documentation hasn't been changed.
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.