I'm trying to write a custom contrain for nunit (3) in vb.net Simplest example (following the docs) would be:
Namespace MYConstraints
Public Class MyConstraint
Inherits NUnit.Framework.Constraints.Constraint
Public Overrides Function ApplyTo(Of TActual)(actual As TActual) As NUnit.Framework.Constraints.ConstraintResult
Throw New NotImplementedException()
End Function
End Class
End Namespace
(The ApplyTo definition was added by Visual Studio automatically even, when I inherited the nunit Constraint class)
Problem is, it won't compile!
I get two errors:
BC30518 Overload resolution failed because no accessible 'That' can be
called with these arguments:
'Public Shared Overloads Sub That(Of TActual)(del As ActualValueDelegate(Of TActual), expr As IResolveConstraint)':
Type parameter 'TActual' cannot be inferred.
'Public Shared Overloads Sub That(Of TActual)(actual As TActual, expression As IResolveConstraint)':
Type parameter 'TActual' cannot be
inferred.
And
BC30935 Member 'Public MustOverride Overloads Function ApplyTo(Of
TActual)(actual As TActual) As ConstraintResult' that matches this
signature cannot be overridden because the class 'Constraint' contains
multiple members with this same name and signature:
'Public MustOverride Overloads Function ApplyTo(Of TActual)(actual As
TActual) As ConstraintResult'
'Public Overridable Overloads Function ApplyTo(Of TActual)(ByRef actual As TActual) As ConstraintResult'
Looking at the nunit source for the Constain class I see that they have defined two variants with the same signature:
/// <summary>
/// Applies the constraint to an actual value, returning a ConstraintResult.
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>A ConstraintResult</returns>
public abstract ConstraintResult ApplyTo<TActual>(TActual actual);
/// <summary>
/// Applies the constraint to an ActualValueDelegate that returns
/// the value to be tested. The default implementation simply evaluates
/// the delegate but derived classes may override it to provide for
/// delayed processing.
/// </summary>
/// <param name="del">An ActualValueDelegate</param>
/// <returns>A ConstraintResult</returns>
public virtual ConstraintResult ApplyTo<TActual>(ActualValueDelegate<TActual> del)
{
#if ASYNC
if (AsyncInvocationRegion.IsAsyncOperation(del))
using (var region = AsyncInvocationRegion.Create(del))
return ApplyTo(region.WaitForPendingOperationsToComplete(del()));
#endif
return ApplyTo(GetTestObject(del));
}
One is abstract with a pass-by-value parameter and the other is virtual with a reference param, but that's surely not enough to distinguish them when calling?
The tooltip error in Visual Studio (VS 2015 Professional if it makes a difference) is:
So it looks like it's interpreting the ActualValueDelegate<TActual> as a ByRef TActual in vb.net
So, two questions:
How is this possible? (Is this allowed in C# but not vb.net? or
have I misunderstood something?) - this is just that I am curious :)
How should I write a custom constrain in vb.net? (Does anyone have
an example?) This is my main question :)
I'm increasingly convinced this is a bug - something valid in C# that doesn't translate to vb.net maybe. Have created a bug at https://github.com/nunit/nunit/issues/2263
It seems to be confirmed as a bug in nunit. See https://github.com/nunit/nunit/issues/2263
Related
I have the following (simplified) situation in my code that I don't fully understand.
''' <summary>
''' Brief minimal replication
''' </summary>
''' <typeparam name="T"></typeparam>
Interface ISpark
Function Swing() As Double
End Interface
Class MySpark : Implements ISpark
Public Function Swing() As Double Implements ISpark.Swing
Throw New NotImplementedException()
End Function
End Class
Interface IMagic(Of T As ISpark)
Function Method() As T
End Interface
Class A(Of T As ISpark) : Implements IMagic(Of T)
Public Function Method() As T Implements IMagic(Of T).Method
Throw New NotImplementedException()
End Function
End Class
Class B(Of T As ISpark) : Inherits A(Of T)
End Class
Class TestingClass
Private MyB As A(Of ISpark)
Sub Initialize()
MyB = New B(Of MySpark)
End Sub
End Class
In my "testing class" I want to construct an object of a type whose inner abstract type has some interface restriction. I understand those work similar as Rust's trait bounds (or I'm at least trying to use them like this here). The issue is that I can only really decide which type to go with at runtime - so I have MySpark and ThySpark and a few other implementations, but only some of them make sense for the parameters given. I therefore want to check what problem I'm dealing with and then decide whether I go with B(Of MySpark)or B(Of ThySpark) or whatever, given that both MySpark and ThySpark implement ISpark. This does however not really work apparently.
My core question boils down to: B inherits from A and MySpark implements ISpark. Why can’t I cast B(Of MySpark) into it? The situation doesn’t change if I require MyB to be B(Of ISpark).
Does anyone have some pointers how I could realise this situation? It's a bit vague, I hope the snippet makes it somewhat clear.
what I'm trying to archive with the code below is to have the GetInstance generic function take in an interface type that SystemVars implements (say IAuthentication) then create an instance of SystemVars and return it as interface type T.
The problem I an having is that no matter what casting method I try I can't find a way to return the new instance of SystemVars as T. The line in the GetInstance method Return <CastingFunction>(New SystemVars,T) always fails to compile with the error message saying Value of type SystemVars cannot be converted to 'T'.
How do I return the instance of the class as the interface type that was passed into T?
Imports System.Drawing
Public Class SystemVars
Implements IAuthentication,
IAuthorization,
IApplicationStarting
Private Sub New()
End Sub
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(New SystemVars, T)
End Function
Public ReadOnly Property Username As String _
Implements IAuthentication.Username,
IAuthorization.Username
Get
Return _userName
End Get
End Property
Public ReadOnly Property Rolls As List(Of String) _
Implements IAuthorization.Rolls
Get
Return _rolls
End Get
End Property
Public ReadOnly Property InstallationId As Guid _
Implements IAuthentication.InstallationId,
IApplicationStarting.InstallationId
Get
Return _installationId
End Get
End Property
Public ReadOnly Property MainWindowStartUpPlacement As Rectangle _
Implements IApplicationStarting.MainWindowStartUpPlacement
Get
Return _mainWindowStartUpPlacement
End Get
End Property
'........
Private Shared _userName As String
Private Shared _rolls As List(Of String)
Private Shared _installationId As Guid
Private Shared _mainWindowStartUpPlacement As Rectangle
End Class
You can make an otherwise illegal cast work by passing through Object.
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(CObj(New SystemVars), T)
End Function
You will get a runtime error if the cast isn't possible; as noted in the comments, this strategy is chucking type safety out the window and basically telling the compiler, "Don't bother me, I know what I'm doing." The runtime will throw an InvalidCastException on failure if you don't test and throw yourself. You can test using Type.IsAssignableFrom if you want to create a more developer-friendly error message; there isn't much context available in the debugger at the point of failure, though it may be pretty obvious if you look up the call stack.
For just three interfaces, it might be better to do three separate specific functions rather than a generic version, especially considering that the functions are necessarily Shared (and thus can't themselves be part of an interface).
You might also consider a design that includes a Dependency Injection container. In this kind of design, there would be a configuration step that would associate the interfaces with SystemVars as the implementation, then the client would ask the container for an instance of the interface and receive a SystemVars object.
The rough way that the three options (the third being to cast the SystemVars object to the requested interface) would look in code is:
'Casting a received object to a requested interface
Dim asInterface = DirectCast(SystemVars.GetInstance(), IAuthorization)
'Using a custom casting function on SystemVars
Dim asInterface = SystemVars.GetInstance(Of IAuthorization)
'Using a DI container
'Behavior if the interface isn't supported depends on the container
Dim asInterface = container.GetInstance(Of IAuthorization)
Note that TryCast could be used instead of DirectCast, in which case the result would be Nothing if the interface isn't supported.
I'm attempting to override the default behavior of the SQL migrations generator so that I may specify a custom foreign key constraint name, as discussed here. I've wired up the configuration as advised.
Unfortunately, however, it's not going so well.
A quick logging statement reveals that the GetFkName() function is never hit.
I tried an alternate configuration construct, as discussed here and here, but I'm getting this error when I attempt to generate a migration:
More than one migrations configuration type was found in the assembly 'ConsoleApp1'. Specify the name of the one to use.
I find this result a bit odd, as I have only one configuration class, one SQL generation class, and one context class (the code below doesn't reflect this, but I commented out the extras for my actual tests). Specifying the configuration type on the command line, as indicated here, errors with this:
System.InvalidOperationException: The type 'ConsoleApp1.Db.CustomDbConfiguration2' does not inherit from 'System.Data.Entity.DbConfiguration'. Entity Framework code-based configuration classes must inherit from 'System.Data.Entity.DbConfiguration'.
All of this brings us back here, then, which doesn't work for the aforementioned reason (GetFkName() never gets hit). So it seems I'm chasing my tail (didn't know I had one until today).
What should I do to get this override to work correctly?
Configuration
Imports System.Data.Entity
Imports System.Data.Entity.Migrations
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomDbConfiguration
Inherits DbConfiguration
Public Sub New()
Me.SetMigrationSqlGenerator(SqlProviderServices.ProviderInvariantName, Function() New CustomSqlGenerator)
End Sub
End Class
Friend Class CustomDbConfiguration2
Inherits DbMigrationsConfiguration(Of Context)
Public Sub New()
Me.SetSqlGenerator(SqlProviderServices.ProviderInvariantName, New CustomSqlGenerator2(Me.GetSqlGenerator(SqlProviderServices.ProviderInvariantName)))
Me.ContextType = GetType(Context)
End Sub
End Class
End Namespace
SQL Generator
Imports System.Data.Entity.Migrations.Model
Imports System.Data.Entity.Migrations.Sql
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomSqlGenerator
Inherits SqlServerMigrationSqlGenerator
Protected Overrides Sub Generate(AddForeignKeyOperation As AddForeignKeyOperation)
AddForeignKeyOperation.Name = GetFkName(AddForeignKeyOperation.PrincipalTable, AddForeignKeyOperation.DependentTable, AddForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(AddForeignKeyOperation)
End Sub
Protected Overrides Sub Generate(DropForeignKeyOperation As DropForeignKeyOperation)
DropForeignKeyOperation.Name = GetFkName(DropForeignKeyOperation.PrincipalTable, DropForeignKeyOperation.DependentTable, DropForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(DropForeignKeyOperation)
End Sub
Private Shared Function GetFkName(PrimaryKeyTable As String, ForeignKeyTable As String, ParamArray ForeignTableFields As String()) As String
IO.File.WriteAllText("D:\Logs\FkNameTest.log", $"{Now.ToString}{vbCrLf}")
Return $"FK_{ForeignKeyTable}_{PrimaryKeyTable}"
End Function
End Class
Friend Class CustomSqlGenerator2
Inherits MigrationSqlGenerator
Public Sub New(Generator As MigrationSqlGenerator)
Me.Generator = Generator
End Sub
Public Overrides Function Generate(MigrationOperations As IEnumerable(Of MigrationOperation), ProviderManifestToken As String) As IEnumerable(Of MigrationStatement)
Return Me.Generator.Generate(MigrationOperations, ProviderManifestToken)
End Function
Private ReadOnly Generator As MigrationSqlGenerator
End Class
End Namespace
Context
Imports System.Data.Common
Imports System.Data.Entity
Imports System.Data.SqlClient
Imports System.Reflection
Namespace Db
<DbConfigurationType(GetType(CustomDbConfiguration2))>
Friend Class Context
Inherits DbContext
Public Sub New()
MyBase.New(DbConnection.ConnectionString)
End Sub
Private Sub New(Connection As DbConnection)
MyBase.New(Connection, True)
Database.SetInitializer(New CreateDatabaseIfNotExists(Of Context))
Database.SetInitializer(New MigrateDatabaseToLatestVersion(Of Context, Migrations.Configuration))
Me.Database.Initialize(False)
End Sub
Public Shared Function Create() As Context
Return New Context(DbConnection)
End Function
Private Shared ReadOnly Property DbConnection As SqlConnection
Get
Return New SqlConnection(Utils.DbConnectionString)
End Get
End Property
Protected Overrides Sub OnModelCreating(Builder As DbModelBuilder)
Builder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly)
MyBase.OnModelCreating(Builder)
End Sub
Public Property Documents As DbSet(Of Document)
Public Property Sections As DbSet(Of Section)
End Class
End Namespace
Disclaimer: I haven't coded in VB for many years, these code examples are my feeble attempt to translate my working example in C# into OPs native VB. Please feel free to update my syntax ;)
You can manually edit the migration scripts to specify a custom name for each ForeignKey by specifying a value for the optional Name parameter in the call to Tablebuilder.ForeignKey as part of a create table statement:
CreateTable(
"dbo.CorporationVariety",
Function(c) New With
{
.Id = c.Int(nullable: false, identity:= true),
.CorporationId = c.Int(nullable:= false),
.VarietyId = c.Int(nullable:= false),
}) _
.PrimaryKey(Function(t) t.Id)
.ForeignKey("dbo.Corporation", Function(t) t.CorporationId, name := "FKCorporatationCorporationVarietyCorporationId")
.ForeignKey("dbo.Variety", Function(t) t.VarietyId, name := "FKVarietyCorporationVarietyVarietyId")
.Index(Function(t) t.CorporationId)
.Index(Function(t) t.VarietyId)
Or as part of a DbMigration.AddForeignKey statement:
AddForeignKey("dbo.CorporationVariety", "CorporationId", "dbo.Corporation", name := "FKCorporatationCorporationVarietyCorporationId")
AddForeignKey("dbo.CorporationVariety", "VarietyId", "dbo.Variety", name := "FKVarietyCorporationVarietyVarietyId")
If you have a lot of keys in your Model, and you want to implement a specific convention, (as in a standard rule or sequence of code that you want to apply in given scenarios) across all keys, then Normally the first place to look for a solution is EF Code First Conventions.
Unfortunately, there is neither a standard convention that can help you here nor can you define a custom name for a foreign key using fluent notation...
Normally we would go ahead and create a Custom Code First Convention to define your custom logic, this works in generally 2 ways:
Your convention executes standard configuration via Fluent Notation
we already noted that this option is not available to us...
Your convention logic stores custom metadata to the model via annotations
Primary and Foreign keys seem to be an anomaly in the EF Code First Runtime, there does not seem to be a way to easily access the annotations from the associations even though they are relatively easy to define.
I was surprised to find this and stumbled across this post that further confirms this: https://stackoverflow.com/a/54369685/1690217
Update I started this post assuming that Conventions was the right way to go, because I use it for many other customisations that I've needed to apply over the years. If you are looking to implement other similar types of customisations, look to Conventions first.
We can still easily override the standard VisualBasicMigrationCodeGenerator that generates the migration code files, so lets jump straight into that.
coapply to custom name for your ForeignKey and then implement a custom MigrationCodeGenerator to process the output from your convention.
Create a custom VisualBasicMigrationCodeGenerator
Register the Code Generator so that it is used by EF to generate the next migration
NOTE: This will not force existing keys in your database to be renamed. To do that you would need to force each key to be dropped and re-added back. For a large model Consider using a T4 template to create custom once-off migration logic to achieve this, once the above steps are in place.
Think of your Custom VisualBasicMigrationCodeGenerator as your personal EF code first sour dough culture, you can share this and re-use it for every new application, adding new functionality and improvements with each iteration. But Conventions are the configuration options that you may not want in every project, (which is why using _Conventions_ for OPs solution was my first direction.)
1. Create a custom VisualBasicMigrationCodeGenerator
Create a new class that inherits from the EF VisualBasicMigrationCodeGenerator, the minimal we need to do is override the AddForeignKeyOperation and modify the Name of the key and call the base implementation. This will affect all new keys added to the model.
To target keys added as part of CreateTable we will have to override GenerateInline(AddForeignKeyOperation...), however the base implemention (in the C# Generator...) doesn't obey the custom Name so instead we have to replace the implementation entirely.
When doing this, goto the EF project on GitHub and start with the original implementation, then inject your customizations as needed.
Please excuse this C#, I didn't have time to translate it, it does generate the correct VB code though ;)
public class CustomVBMigrationCodeGenerator : System.Data.Entity.Migrations.Design.VisualBasicMigrationCodeGenerator
{
protected override void Generate(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
ApplyCustomFKName(addForeignKeyOperation);
base.Generate(addForeignKeyOperation, writer);
}
private void ApplyCustomFKName(ForeignKeyOperation operation)
{
// expecting FK without scheme or underscores: "FK{DependentTable}{PrincipalTable}{FKField}"
operation.Name = $"FK{StripSchemeFromName(operation.DependentTable)}{StripSchemeFromName(operation.PrincipalTable)}{String.Join("", operation.DependentColumns)}";
}
private string StripSchemeFromName(string dbObjectName)
{
return dbObjectName.Split(new[] { '.' }, 2).Last();
}
/// <summary>
/// Generates code to perform an <see cref="AddForeignKeyOperation" /> as part of a <see cref="CreateTableOperation" />.
/// </summary>
/// <param name="addForeignKeyOperation"> The operation to generate code for. </param>
/// <param name="writer"> Text writer to add the generated code to. </param>
protected virtual void GenerateInline(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
// sourced from https://github.com/aspnet/EntityFramework6/blob/master/src/EntityFramework/Migrations/Design/VisualBasicMigrationCodeGenerator.cs
Check.NotNull(addForeignKeyOperation, "addForeignKeyOperation");
Check.NotNull(writer, "writer");
writer.WriteLine(" _");
writer.Write(".ForeignKey(" + Quote(addForeignKeyOperation.PrincipalTable) + ", ");
Generate(addForeignKeyOperation.DependentColumns, writer);
// Our Custom logic
ApplyCustomFKName(addForeignKeyOperation);
// Insert our custom name if provided
if (!addForeignKeyOperation.HasDefaultName)
{
writer.Write(", name := " + Quote(addForeignKeyOperation.Name));
}
if (addForeignKeyOperation.CascadeDelete)
{
writer.Write(", cascadeDelete := True");
}
writer.Write(")");
}
}
2. Register the Code Generator so that it is used by EF to generate the next migration
Locate Configuration.vb in your project, int the constructor set the CodeGenerator to an instance of your CustomVBMigrationCodeGenerator :
Public Sub New()
AutomaticMigrationsEnabled = false
CodeGenerator = new CustomVBMigrationCodeGenerator()
End Sub
Now execute the add-migration to generate a new migration you will see you new custom name defined in the migration script.
You may be required to similarly override the Generate(DropForeignKeyOperation...) methods as well if you need to downgrade from this configuration _or_ if alter table commands require the key to be dropped first.
I have this method at my Hub:
Public Sub SaveFields(ByVal changeSignal As String)
Dim foo As Integer = 5
End Sub
If I call it from client-side like this:
testHub.server.saveFields("abc");
then SaveFields is called successfully. However, if I have a Class like this:
Public Class WOChangeSignal
Public WOID As Integer
Public FieldUpdates As Dictionary(Of String, String)
End Class
and add an overload for SaveFields like this:
Public Sub SaveFields(ByVal changeSignal As WOChangeSignal)
Dim foo As Integer = 5
End Sub
Public Sub SaveFields(ByVal changeSignal As String)
Dim foo As Integer = 5
End Sub
then my call of
testHub.server.saveFields("abc");
will be unsuccssful, just like my call of
testHub.server.saveFields({
WOID: 1234,
FieldUpdates: [
{Key: 2, Value: 4},
{Key: 3, Value: 5}
]
});
as none of these tries are actually invoking the server-side method. As a consequence, I assume that the problem is the overload which expects an instance of a Class. So, my question is as follows: why is SignalR not invoking none of the overloads if I add an overload expecting WOChangeSignal parameter?
It turns out that this is the cause:
/// <summary>
/// Searches the specified <paramref name="hub">Hub</paramref> for the specified <paramref name="method"/>.
/// </summary>
/// <remarks>
/// In the case that there are multiple overloads of the specified <paramref name="method"/>, the <paramref name="parameters">parameter set</paramref> helps determine exactly which instance of the overload should be resolved.
/// If there are multiple overloads found with the same number of matching parameters, none of the methods will be returned because it is not possible to determine which overload of the method was intended to be resolved.
/// </remarks>
/// <param name="hub">Hub to search for the specified <paramref name="method"/> on.</param>
/// <param name="method">The method name to search for.</param>
/// <param name="descriptor">If successful, the <see cref="MethodDescriptor"/> that was resolved.</param>
/// <param name="parameters">The set of parameters that will be used to help locate a specific overload of the specified <paramref name="method"/>.</param>
/// <returns>True if the method matching the name/parameter set is found on the hub, otherwise false.</returns>
public bool TryGetMethod(HubDescriptor hub, string method, out MethodDescriptor descriptor, IList<IJsonValue> parameters)
{
string hubMethodKey = BuildHubExecutableMethodCacheKey(hub, method, parameters);
if (!_executableMethods.TryGetValue(hubMethodKey, out descriptor))
{
IEnumerable<MethodDescriptor> overloads;
if (FetchMethodsFor(hub).TryGetValue(method, out overloads))
{
var matches = overloads.Where(o => o.Matches(parameters)).ToList();
// If only one match is found, that is the "executable" version, otherwise none of the methods can be returned because we don't know which one was actually being targeted
descriptor = matches.Count == 1 ? matches[0] : null;
}
else
{
descriptor = null;
}
// If an executable method was found, cache it for future lookups (NOTE: we don't cache null instances because it could be a surface area for DoS attack by supplying random method names to flood the cache)
if (descriptor != null)
{
_executableMethods.TryAdd(hubMethodKey, descriptor);
}
}
return descriptor != null;
}
As we can see, if there is not exactly a single match, then descriptor will be null. It turns out that this is by design and the reason given is as follows:
If only one match is found, that is the "executable" version,
otherwise none of the methods can be returned because we don't know
which one was actually being targeted
is there a way to extend the existing binding syntax (e.g. extension method) that will allow us to have something like this:
Bind<IRepository>().ToProvider<MyProvider<MyRepository>>().WhenCustom<SomeType>()
Write an extension method for IBindingWhenSyntax<T> and use the existing When overload to implement your logic:
class BindingWhenExtensions
{
public IBindingInNamedWithOrOnSyntax<T> WhenCustom<T>(
this IBindingWhenSyntax<T> syntax)
{
return syntax.When(r => true);
}
}
Reframing the question (to align with your comment) you want to create an extension with a signature similar to the following;
public static IBindingInNamedWithOrOnSyntax<T> WhenCustom<TParent>(
this IBindingWhenSyntax<T> binding)
As far as I can tell we're not able to extend as cleanly as this with Ninject because as you rightly allude to T here is defined on an interface that our extension doesn't know about.
So our extension signature must be;
public static IBindingInNamedWithOrOnSyntax<T> WhenCustom<T>(
this IBindingWhenSyntax<T> binding)
At this point the only way I see us being able to successfully pass TParent is to drop the generic parameter and pass it as a standard type parameter (or pass several types);
public static IBindingInNamedWithOrOnSyntax<T> WhenCustom(
this IBindingWhenSyntax<T> binding, params Type[] parents)
This is still consistent with Ninjects own binding syntax methods;
/// <summary>
/// Indicates that the binding should be used only for injections on the specified types.
/// Types that derive from one of the specified types are considered as valid targets.
/// Should match at lease one of the targets.
/// </summary>
/// <param name="parents">The types to match.</param>
/// <returns>The fluent syntax.</returns>
IBindingInNamedWithOrOnSyntax<T> WhenInjectedInto(params Type[] parents);
It's just unfortunate that we don't have the luxury of extending with 'pure' generics.