Anonymous Function Showing End Function Warning - vb.net

I am trying out FluentValidation, and I'm converting a C# RuleSet example to VB.NET.
Question: Why is VS 2019 putting the green squiggly line under End Function, stating the function doesn't return a value on all code paths. Should I be doing something more in the anonymous function to remove this warning? Just ignore it?
Here is the original C# example:
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleSet("Names", () => {
RuleFor(x => x.Surname).NotNull();
RuleFor(x => x.Forename).NotNull();
});
}
}
Here is my conversion and application in VB.NET, with my own class ContractDTO:
Public Class ContractValidator
Inherits AbstractValidator(Of ContractDTO)
Public Sub New()
RuleSet("OnCreate",
Function()
RuleFor(Function(x) x.CustomerID).NotEmpty
End Function ' Green squiggly line warning here.
)
End Sub
End Class
EDIT: Note that "Show potential fixes" in Visual Studio shows nothing.

A function needs to return a value. Yours doesn't, therefore, you should use Sub/End Sub instead:
Public Class ContractValidator
Inherits AbstractValidator(Of ContractDTO)
Public Sub New()
RuleSet("OnCreate",
Sub()
RuleFor(Function(x) x.CustomerID).NotEmpty
' Add more lines.
End Sub)
End Sub
End Class
If you don't need more lines inside your sub, you may get rid of the End Sub part like so:
RuleSet("OnCreate", Sub() RuleFor(Function(x) x.CustomerID).NotEmpty)

Related

Method 'set_Description' in type 'myAssembly.NetProduct' from assembly 'myAssembly' does not have an implementation

I have a DLL file created in VB6. It contains a class named Product and that contains the following simple code:
Option Explicit
Private sDescription As String
Public Property Get Description() As String
Description = sDescription
End Property
Public Property Let Description(Value As String)
sDescription = Value
End Property
I want to use this DLL in VB.NET, which is nothing more than registering the DLL on my system and including the DLL file in the references. Visual Studio automatically generates an interop DLL to consume the COM DLL. This interop DLL generates interfaces for all classes. In VB.NET I want to create a new class that implements the Product interface from the interop DLL. So I code:
Imports myAssembly
Public Class NetProduct
Implements myAssembly.Product
Public Property Description As String Implements _Product.Description
Get
Throw New NotImplementedException()
End Get
Set(value As String)
Throw New NotImplementedException()
End Set
End Property
End Class
The property is auto-generated because I implemented the Product interface. But here comes the problem because when I start using the NetProduct class I get an error telling me this:
Method 'set_Description' in type 'myProject.NetProduct' from
assembly 'myProject, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null' does not have an implementation.
The problem is that there is no method set_Description in the interface. When I view the definition of the Product interface it shows me the following:
Imports System.Runtime.InteropServices
Namespace myAssembly
<CoClass(GetType(ProductClass))> <Guid("49CE2F98-931C-441B-B322-9F39B6D6F212")>
Public Interface Product
Implements _Product
End Interface
End Namespace
The definition of the _Product interface is:
Imports System.Runtime.InteropServices
Namespace myAssembly
<Guid("49CE2F98-931C-441B-B322-9F39B6D6F212")> <TypeLibTypeAttribute(4304)>
Public Interface _Product <DispId(1745027072)>
Property Description As String
End Interface
End Namespace
When I use the interface myAssembly.Product directly to create a new object then everything works as you would expect. The property does not pose a problem there. But when I implement the interface in a .NET class the problem arises.
How do I solve this?
[update 1] After creating a method Set_Description I see the following error appear:
property 'Description' implicitly defines 'set_Description', which
conflicts with a member of the same name in class 'NetProduct'.
This must have something to do with my problem, although I don't know what it is. I already tried completing the property to make sure the Throw New NotImplementedException() wouldn't be in the way but that didn't make the error go away. My code builds just fine by the way. The error I gave earlier is a runtime error. Not a build error.
Private myDescription As String
Public Property Description As String Implements Product.Description
Get
Return myDescription
End Get
Set(value As String)
myDescription = value
End Set
End Property
[update 2] I have used JetBrains DotPeek to disassemble the interop.dll that Visual Studio generates. Disassembly is coded in C#. It contains 2 interfaces and 1 class for the single Product class from VB6. Here are all details.
I'll start with the Product class itself.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace myAssembly
{
[ClassInterface(0)]
[Guid("C54B96A8-1499-4B76-8508-0B732E551326")]
[TypeLibType(2)]
[ComImport]
public class ProductClass : _Product, Product
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public extern ProductClass();
[DispId(1745027072)]
public virtual extern string Description { [DispId(1745027072), MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [return: MarshalAs(UnmanagedType.BStr)] get; [DispId(1745027072), MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [param: MarshalAs(UnmanagedType.BStr), In, Out] set; }
}
}
The ProductClass uses 2 interfaces. I don't understand why because one of those is just an implementation of the other. This is the Product interface.
using System.Runtime.InteropServices;
namespace myAssembly
{
[CoClass(typeof (ProductClass))]
[Guid("49CE2F98-931C-441B-B322-9F39B6D6F212")]
[ComImport]
public interface Product : _Product
{
}
}
And then we have the _Product interface. They even share the same Guid. It might have something to do with backwards compatibility.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace myAssembly
{
[Guid("49CE2F98-931C-441B-B322-9F39B6D6F212")]
[TypeLibType(4304)]
[ComImport]
public interface _Product
{
[DispId(1745027072)]
string Description { [DispId(1745027072), MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [return: MarshalAs(UnmanagedType.BStr)] get; [DispId(1745027072), MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [param: MarshalAs(UnmanagedType.BStr), In, Out] set; }
}
}
This is all I could find. Still no clue where the error for Set_Description comes from.
[Update 3] Example code
The code for the VB6 class is on top of this question. Nothing fancy there. The code for testing implementation in .NET is like this:
Imports myAssembly
Public Class NetProduct
Implements myAssembly.Product
Private myDescription As String
Public Property Description As String Implements Product.Description
Get
Return myDescription
End Get
Set(value As String)
myDescription = value
End Set
End Property
End Class
To test the NetProduct class I dropped a Button on a Form and create an instance of the class when the button is being clicked.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '<- Error happens here, so on loading the datatype!
Dim Product As New NetProduct 'Error does NOT happen here.
End Sub
The whole project compiles without errors. The project even runs without errors UNTIL you click the button. Probably because the NetProduct type is first loaded on that point.
I used a console app to do my test. Other than that, my VB.NET code is basically identical to yours in update 3. The VB.NET properties were auto-generated by VS with the stub Throw New NotImplementedException() after using the Implements statement :
Imports OurCOMDll
Class TestClass
Implements OurCOMDll.ClassInCOMDll
Dim msStringProperty As String = String.Empty
Public Property StringProperty As String Implements _ClassInCOMDll.StringProperty
Get
StringProperty= msStringProperty
End Get
Set(value As String)
msStringProperty = value
End Set
End Property
End Class
Module Module1
Sub Main()
Dim o As New OurCOMDll.ClassInCOMDll
o.StringProperty = "Hello World!"
Console.WriteLine(o.StringProperty) ' Outputs 'Hello World!' as expected
Console.ReadLine()
End Sub
End Module
Same is true for the VB6 code. The string property is implemented like yours.
Distinguishing factors so far:
VS 2019 vs. VS 2017
(Consuming) GUI vs. Console application
Different property names

FluentValidation Custom Function within Validator Class

Using this example from the FluentValidation website, I'm converting the concept to VB.NET using my own classes. The part in interest to my issue is the Must(BeOver18), which calls the protected function. Note that this call doesn't pass a parameter to BeOver18:
public class PersonAgeValidator : AbstractValidator<Person> {
public PersonAgeValidator() {
RuleFor(x => x.DateOfBirth).Must(BeOver18);
}
protected bool BeOver18(DateTime date) {
//...
}
}
I created my own validator class in VB.NET like this, using the same principal as above but instead for a function called CustomerExists:
Public Class ContractValidator
Inherits AbstractValidator(Of ContractDTO)
Public Sub New()
RuleSet("OnCreate",
Sub()
RuleFor(Function(x) x.CustomerID).NotEmpty
' Compiler error here:
' BC30455 Argument not specified for parameter 'customerID'.....
RuleFor(Function(x) x.CustomerID).Must(CustomerExists)
End Sub
)
End Sub
Protected Function CustomerExists(customerID As Integer) As Boolean
Return CustomerService.Exists(customerID)
End Function
End Class
ISSUE: The line in VB.NET with .Must(CustomerExists) is giving the "Argument not specified for parameter 'customerID'..." compiler error. The C# example does not pass a parameter to BeOver18. I tried an additional anonymous in-line function to try to pass ContractDTO.CustomerID, but it doesn't work as it's not recognized:
' This won't work:
RuleFor(Function(x) x.CustomerID).Must(CustomerExists(Function(x) x.CustomerID))
I'm at a loss on how the C# example can call it's function without a parameter, but the VB.NET conversion cannot. This is where i need help.
Your CustomerExists function needs to be treated as a delegate. In order to do that, change the following:
Original
RuleFor(Function(x) x.CustomerID).Must(CustomerExists)
Update
RuleFor(Function(x) x.CustomerID).Must(AddressOf CustomerExists)

VB.Net - Passing function with return value through constructor

I have an app which uses about 89 different UserControls with very similar methods. I have made a base class for these UserControls with the similar methods within. Four of these methods call a function for selecting, inserting, deleting, and updating database records. My idea to handle this was to pass in these four database functions as parameters to the base class, and reference them in these base methods when I need them. Pseudo Code:
Public MustInherit Class MyAbstractBaseClass
Inherits UserControl
// Protected DatabaseInsertFunction(Of IDBRecord) As Boolean
// Protected DatabaseDeleteFunction(Of IDBRecord) As Boolean
// Protected DatabaseSelectFunction(Of IDBRecord) As Boolean
// Protected DatabaseUpdateFunction(Of IDBRecord) As Boolean
Public Sub New( InsertFunc, ...)
// Me.DatabaseInsertFun = InsertFun
...
End Sub
Protected Sub DoWork(someObject As IDBRecord)
// Do some work here
Dim result As Boolean = DatabaseInsertFunction(someObject)
...
End Sub
End Class
Public Class MyDerivedClass
Inherits MyAbstractBaseClass
Public Sub New()
MyBase.New(AddressOf InsertRecord)
End Sub
Private Sub InsertRecord(someObj as IDBRecord) As Boolean
// some work here
End Sub
End Class
I have tried every variation of syntax I can find on Google and it continues to elude me. Looking at the above code snippet, I would like to pass in the function from the derived class to the base class upon construction and store it in the base' class fields so that they can be called upon by different methods within the base class later. Using Func(Of T) is great except when there are return values I can't figure it out. Any help would be much appreciated

Migratordotnet : How to write a migration class with VB.net?

I got all C# implementations on Google, so I converted it to VB.Net, but I am not able to convert 1 line where it gives error.
My Class :
Imports Migrator.Framework
[Migration(1)] ' Gives ERROR Here.. How to write this in VB.net ?
Public Class mig_001
Inherits Migration
Public Overrides Sub Up()
Database.AddTable("Planets",
New Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
New Column("Name", DbType.String, 100, ColumnProperty.NotNull),
New Column("Diameter", DbType.Double),
New Column("Mass", DbType.Double),
New Column("SupportsLife", DbType.Boolean, False)
)
End Sub
Public Overrides Sub Down()
Database.RemoveTable("Planets")
End Sub
End Class
Once again :
[Migration(1)] => How to write this in VB.net and what does it means in VB.net ?
I read in an article that its mandatory for version of Migration, otherwise Migratordotnet will miss the migration.
So.. How to do it ?
Like this:
<Migration(1)> _
Public Class mig_001
This <…> feature, belonging to the following class, is called an attribute in .NET.

Adding a global function

I am trying to add a new global function
I am doing it like that:
Function MessageYNC() As String
{
return "dd";
}
End Function
Public Class SatelliteAPI
End Class
But i am getting error -> Statement is not valid in a namespace.
on the first line
Any idea what is wrong ?
The function belongs inside
the class.
The curly
braces and semicolons don't belong
in VB. Those are C#.
In
order for your method to be global,
you will need to declare it as
Shared. If your entire class
consists of nothing but shared
methods, you may consider creating a
module as opposed to a class.
Here's an explanation of the
difference between a class with
shared methods and a module.
Public Class SatelliteAPI
Public Shared Function MessageYNC() As String
Return "dd"
End Function
End Class 'SatelliteAPI
Public Class TestClass
Public Sub TestMessageMethod()
Console.WriteLine(SatelliteAPI.MessageYNC)
End Sub
End Class 'TestClass
Put the function into a class or module. If you put it into a class, you need to make it Shared. So it's either
Module MyFunctions
Function MessageYNC() As String
Return "dd"
End Function
End Module
or
Public Class SatelliteAPI
Shared Function MessageYNC() As String
Return "dd"
End Function
End Class
in which case you would access it as StaelliteAPI.MessageYNC.