I want to experiment with a simple bit of code found here:
http://msdn.microsoft.com/en-au/library/ff664617%28v=pandp.50%29.aspx
But I cannot get it to compile, I must be doing something wrong. About a third of the way down the page it gives a code sample like this:
'Usage exManager.Process(Function() method-name(param1, param2), _
"Exception Policy Name")
But if I enter the following code:
Dim exManager As ExceptionManager
exManager = EnterpriseLibraryContainer.Current.GetInstance(Of ExceptionManager)()
exManager.Process(Function() TestSub(), "Exception Policy Name")
I get an error on the third line that says:
Overload resolution failed because no accessible 'Process' can
be called with these arguments:
'Public Overridable Function Process(Of TResult)(action As System.Func(Of TResult), policyName As String) As TResult': Cannot
refer to an instance member of a class from within a shared method or
shared member initializer without an explicit instance of the class.
'Public Overridable Function Process(Of TResult)(action As System.Func(Of TResult), policyName As String) As TResult': Data
type(s) of the type parameter(s) cannot be inferred from these
arguments. Specifying the data type(s) explicitly might correct this
error.
etc.
Even if I try to modify the lambda like this:
exManager.Process(Function() Dim A As Integer=6, "Exception Policy Name")
I get a similar error.
Any comments would be appreciated.
UPDATE:
Note I am compiling for .NET Framework 4 Client Profile
You are using the Process(Of TResult) overload when you call exManager.Process(Function() TestSub(), "Exception Policy Name").
The method is generic and expects and type argument (TResult), which in a lot of cases can be inferred by the compiler. Now the exception tells you that, in your case, the compiler can infer TResult.
I guess your TestSub is really a Sub and therefore has no return value which the compiler could use to infer TResult.
So use the non-generic Process method by either using Sub instead of Function
exManager.Process(Sub() TestSub(), "Exception Policy Name")
or simply use AddressOf:
exManager.Process(AddressOf TestSub, "Exception Policy Name")
Related
I'm using generics to not reuse code and I' running into a lack of understanding for type generics. I have a class Writer (java code from another library).
public class Writer<T>
A class FileWriter (java code from another library)
public class FileWriter<D>{
FileWriter(Writer<D> writer){
this.writer=writer
}
public void append(D datum){
//Does something
}
}
Now I'm initiating this in kotlin:
val writer = FileWriter(Writer(AGenratedJavaClassThatIMplementsSpecificRecord::class.java))
I can now call writer.append with AGenratedJavaClassThatIMplementsSpecificRecord(). It works just fine
I would like to pass this writer to a function.
funDoSomethingExtra(writer: FileWriter<in SpecificRecord>)
This gives me an error that I do not understand.
Type mismatch: inferred type is FileWriter<AGenratedJavaClassThatIMplementsSpecificRecord!>! but FileWriter<in SpecificRecord> was expected
Changing this to
funDoSomethingExtra(writer: FileWriter<out SpecificRecord>)
Makes writers.append give the error
Required Nothing, found AGenratedJavaClassThatIMplementsSpecificRecord.
Without the use of methods, all works fine. Which details Am I missing? It is probably something small,
Kind regards,
Jelmew
This line of your code:
val writer = FileWriter(Writer(AGenratedJavaClassThatIMplementsSpecificRecord::class.java))
does not specify the type of the FileWriter, so it is inferred from your arguments to the constructors, so the type of writer is FileWriter<AGenratedJavaClassThatIMplementsSpecificRecord>.
Your signature funDoSomethingExtra(writer: FileWriter<in SpecificRecord>) is correct for calling a method on the writer that does something to a SpecificRecord or subtype of SpecificRecord. However, your
FileWriter<AGenratedJavaClassThatIMplementsSpecificRecord>
cannot be cast to a FileWriter<in SpecificRecord> because AGenratedJavaClassThatIMplementsSpecificRecord is a subtype of SpecificRecord, not a supertype. The compiler knows your file writer can consume AGenratedJavaClassThatIMplementsSpecificRecord, but it doesn't know it can consume the less-specific type SpecificRecord. There's the possibility of you calling some function of the subtype that doesn't exist in the supertype.
So to be able to pass your writer to this function, it needs to be a FileWriter<SpecificRecord> or FileWriter<in SpecificRecord>. You can't safely cast it after its type is already assigned, but you can assign it the proper type right at the declaration site instead of letting the compiler try to infer it:
val writer: FileWriter<SpecificRecord> = FileWriter(Writer(AGenratedJavaClassThatIMplementsSpecificRecord::class.java))
I'm working with code that references a library that has an optional NLog.Logger as a parameter (the code for this library with this method definition was lost so I have to recreate it). The code below complains with this message: "Error 41 Constant expression is required." I can't figure out how to make this work though as I've tried to define a Const, as well as just setting the default value to null and nothing works. How do I create an option parameter of type Logger? Thanks!
Dim objTraceLogDefault As Logger = LogManager.GetLogger("TraceFile")
Public Function MyFunction(Optional ByVal objTraceLog As Logger =
objTraceLogDefault)
Optional parameters should be constants, (e.g. numbers, strings or Nothing), because the compiler add the constant values add compile time.
You could set the default to Nothing and check for Nothing in the body.
Private Function MyFunction(ByVal Optional objTraceLog As Logger = Nothing)
objTraceLog = If(objTraceLog, objTraceLogDefault)
End Function
I updated an AutoMapper V3.3.1 to V6.1.1 and much to my surprise, after putting all CreateMaps() in a profile, it actually worked perfectly right out of the gate – almost scary for me.
The problem that I am having is that it IS working with the code below as is suggested in the AutoMapper documentation:
Private Sub InitiatizeAutoMapper()
Mapper.Initialize(Function(cfg)
cfg.AddProfile(Of MappingProfile)()
End Function)
End Sub
But the code issues a warning:
Warning BC42105 Function '<anonymous method>' doesn't return a value on all code paths. A null reference exception could occur at run time when the result is used.
If I add a Return to the Lambda like:
Private Sub InitiatizeAutoMapper()
Mapper.Initialize(Function(cfg)
Return cfg.AddProfile(Of MappingProfile)()
End Function)
End Sub
I then get the following error:
Error BC30518 Overload resolution failed because no accessible 'Initialize' can be called with these arguments:
'Public Shared Overloads Sub Initialize(config As Action(Of IMapperConfigurationExpression))': Expression does not produce a value.
'Public Shared Overloads Sub Initialize(config As Action(Of IMapperConfigurationExpression))': Expression does not produce a value.
'Public Shared Overloads Sub Initialize(config As MapperConfigurationExpression)': Lambda expression cannot be converted to 'MapperConfigurationExpression' because 'MapperConfigurationExpression' is not a delegate type.
Now - if I make it a Sub instead of a function, it all works well with no errors like this:
Private Sub InitiatizeAutoMapper()
Mapper.Initialize(Sub(cfg)
cfg.AddProfile(Of MappingProfile)()
End Sub)
End Sub
I know that this will probably be a head-slapper but I am trying to follow the documentation and am afraid to release this into production in that I might be missing something.
EDIT:
I chose to break down the multiline lambda to make it a little easier for me, which also avails IntelliSense options quite handily for future enhancement. While it is probably not the "coolest" code, I find it very readable.
Private Sub InitiatizeAutoMapper()
Dim config As New Configuration.MapperConfigurationExpression : With config
.AddProfile(Of MappingProfile)()
End With
Mapper.Initialize(config)
End Sub
The whole point of a Function is that it returns something. In your first code snippet, what is your anonymous function returning? It isn't returning anything because it has no Return statement. There's no point arbitrarily adding a Return statement if you don't actually have anything to return and you can't return the result of AddProfile if that doesn't return anything itself. Basically, your lambda doesn't return anything and what do we call a method that doesn't return anything? It's a Sub.
You'll notice in the error message you posted that the Initialize method overloads that take a delegate as an argument are expecting an Action, not a Func. Action delegates are created with a Sub while a Function is used to create a Func delegate.
So I have the following line of code in c# to register AutoMapper with SimpleInjector:
container.Register(() => config.CreateMapper(container.GetInstance));
For context, config.CreateMapper() looks like this:
public IMapper CreateMapper(Func<Type, object> serviceCtor);
While container.GetInstance looks like this:
public object GetInstance(Type serviceType);
The first line of code I posted works in C# because config.CreateMapper takes in a function that takes a type of Type and returns a type of object. Exactly what container.GetInstance does.
When I try to do this same line in VB, as:
container.Register(Function() config.CreateMapper(container.GetInstance))
It gives an error Type arguments for 'Public Function Container.GetInstance(Of TService)()' cannot be inferred from the usage. Try specifying type arguments explicitly. It is giving this error because container.GetInstance has an overload that looks like this:
public TService GetInstance<TService>() where TService : class;
Why does the VB try to use the wrong overload of GetInstance and how can I force it to use the correct one?
Use AddressOf for getting function reference.
container.Register(Function() config.CreateMapper(AddressOf container.GetInstance))
In C# function with parenthesis executes it, function without parenthesis will return reference to the function.
In VB.NET parenthesis in function are optional - function will be executed anyway. So for referencing a function you should use AddressOf operator.
AddressOf Operator
Use the AddressOf keyword before the function parameter to define this as Parameter as function pointer.
AddressOf ist the same as # keyword in C#. The keyword is implicit used in your c# sample.
Updated with new code:
I've got some very simple Linq using Entities
Return NDCEntity.tbl_Ext_Mobile_PO.Where(Function(p) If(p.AssignedToUID, 0) = UserUID)
I can do that in C# without trouble by simple replacing Function(p) with p =>. But in VB.NET there's an added problem. If I try doing the above with Option Strict ON, then i get this massive compiler error.
I tried the solution suggested over at Entity Framework Where method parameters and changed my code to have the If(p.AssignedToUID, 0) but that gives me a very similar error.
Which is apparently some kind of casting error. I've seen several variations of people asking about this on this site and others, but none of the ones I found actually answer it: what do you have to do to make this work with Option Strict ON? I much prefer to work with it on.
Update:
Here's the error text:
Error 1 Overload resolution failed because no accessible 'Where' can be called with these arguments:
'Public Function Where(predicate As String, ParamArray parameters() As System.Data.Objects.ObjectParameter) As System.Data.Objects.ObjectQuery(Of tbl_Ext_Mobile_PO)': Lambda expression cannot be converted to 'String' because 'String' is not a delegate type.
Extension method 'Public Function Where(predicate As System.Func(Of tbl_Ext_Mobile_PO, Integer, Boolean)) As System.Collections.Generic.IEnumerable(Of tbl_Ext_Mobile_PO)' defined in 'System.Linq.Enumerable': Nested function does not have a signature that is compatible with delegate 'System.Func(Of tbl_Ext_Mobile_PO, Integer, Boolean)'.
Extension method 'Public Function Where(predicate As System.Func(Of tbl_Ext_Mobile_PO, Boolean)) As System.Collections.Generic.IEnumerable(Of tbl_Ext_Mobile_PO)' defined in 'System.Linq.Enumerable': Cannot infer a common type, and Option Strict On does not allow 'Object' to be assumed.
Extension method 'Public Function Where(predicate As System.Linq.Expressions.Expression(Of System.Func(Of tbl_Ext_Mobile_PO, Integer, Boolean))) As System.Linq.IQueryable(Of tbl_Ext_Mobile_PO)' defined in 'System.Linq.Queryable': Nested function does not have a signature that is compatible with delegate 'System.Func(Of tbl_Ext_Mobile_PO, Integer, Boolean)'.
Extension method 'Public Function Where(predicate As System.Linq.Expressions.Expression(Of System.Func(Of tbl_Ext_Mobile_PO, Boolean))) As System.Linq.IQueryable(Of tbl_Ext_Mobile_PO)' defined in 'System.Linq.Queryable': Cannot infer a common type, and Option Strict On does not allow 'Object' to be assumed. C:\Programming\Sources\NDC\Custom Web Services\Mobile SAP WebServices\1.0.0.0\MobileSAPWebServices\MobileSAPWebServices\SAPMobileWS.asmx.vb 29 20 MobileSAPWebServices
Should I be DirectCasting this to something?
See my edit.
Try this:
Return NDCEntity.tbl_Ext_Mobile_PO.Where(Function(p) If(p.AssignedToUID.HasValue, p.AssignedToUID.Value, 0) = UserUID)
think the issue might be that VB can't correctly infer that p is always going to be an Integer and instead guesses that it is nullable. You can also try DirectCast, Convert.ToInt32, or CInt like so:
Return NDCEntity.tbl_Ext_Mobile_PO.Where(Function(p) DirectCast(If(p.AssignedToUID, 0), Integer) = UserUID)
EDIT: You are comparing Object to Guid, since p can evaluate to either a Guid or 0. Change the zero to a Guid and you should be good to go. Try this:
Return NDCEntity.tbl_Ext_Mobile_PO.Where(Function(p) If(p.AssignedToUID, Guid.Empty) = UserUID)
OR
Return NDCEntity.tbl_Ext_Mobile_PO.Where(Function(p) If(p.AssignedToUID, Nothing) = UserUID)