How to dynamically invoke a chain of delegates in VB.NET - vb.net

Does someone knows if it's possible to dynamically create a call chain and invoke it?
Lets say I have two classes A & B:
public class A
public function Func() as B
return new B()
end function
end class
public class B
public function Name() as string
return "a string";
end function
end class
I want to be able to get MethodInfo for both Func() & Name() and invoke them dynamically so that I can get a call similar to A.Func().Name().
I know I can use Delegate.CreateDelegate to create a delegate I can invoke from the two MethodInfo objects but this way I can only call the two functions separately and not as part of a call chain.
I would like two solutions one for .NET 3.5 using expression tree and if possible a solution that is .NET 2.0 compatible as well

Are you using .NET 3.5? If so, it should be relatively straightforward to build an expression tree to represent this. I don't have enough expression-tree-fu to easily write the relevant tree without VS open, but if you confirm that it's an option, I'll get to work in notepad (from my Eee... hence the lack of VS).
EDIT: Okay, as an expression tree, you want something like (C# code, but I'm sure you can translate):
// I assume you've already got fMethodInfo and nameMethodInfo.
Expression fCall = Expression.Call(null, fMethodInfo);
Expression nameCall = Expression.Call(fCall, nameMethodInfo);
Expression<Func<string>> lambda = Expression.Lambda<Func<string>>(nameCall, null);
Func<string> compiled = lambda.Compile();
This is untested, but I think it should work...

You need t add this line before the 1st expression:
Expression ctorCall = Expression.Constructor(A)
And pass that expression as the 1st parameter when creating fCall
Otherwise we're missing a starting point for the chain and we'll get an exception when running the code

Related

Using a function without returning a value visual basic

I'm making a batch development kit in visual basic and i need to be able to call a function that sets textboxes to a saved files text. How do i do this without returning? I tried this, and it lets me run the program, but gives me a warning, not an error. How do i go about doing this? Here is my little function design. P.S. I recently switched back to VB from Java and i'm so used to doing public void. Thanks in advance!
Public Function loadProject()
End Function
You want a Sub, which is the equivalent to the Java void method.
Public Sub LoadProject()
End Sub
It's not a bad Idea to just have a function that returns a value like a success statement just in case you need it. A call to the function doesn't have to accept or use the return value from the function.
You could even build a class with two values - txtpreviousvalue and txtnewvalue
Have your function return that type and fill an instance of the type with the respective values.
One day, if you need it, you'll have it.
P.S. I'm only posting this as an answer because the good answer posted by sstan is not marked as the answer; You should probably do that.

lua modules - what's the difference between using ":" and "." when defining functions? [duplicate]

This question already has answers here:
Difference between . and : in Lua
(3 answers)
Closed 8 years ago.
I'm still playing around with lua modules and I've found the following "interesting" issue that occurs depending on how you create your methods / functions inside a module.
Note the following code in a file called test_suite.lua:
local mtests = {} -- public interface
function mtests:create_widget(arg1)
print(arg1)
-- does something
assert(condition)
print("TEST PASSED")
end
return mtests
Using the above code, arg1 is always nil, no matter what I pass in when calling create_widget(). However, if I change the definition of the function to look like this:
function mtests.create_widget(arg1) -- notice the period instead of colon
print(arg1)
-- does something
assert(condition)
print("TEST PASSED")
end
then, the system displays arg1 properly.
This is how I call the method:
execute_test.lua
local x = require "test_suite"
x.create_widget(widgetname)
Can you tell me what the difference is? I've been reading: http://lua-users.org/wiki/ModuleDefinition
But I haven't come across anything that explains this to me.
Thanks.
All a colon does in a function declaration is add an implicit self argument. It's just a bit of syntactic sugar.
So if you're calling this with (assuming you assign the mtests table to foo), foo.create_widget(bar), then bar is actually assigned to self, and arg1 is left unassigned, and hence nil.
foo = {}
function foo:bar(arg)
print(self)
print(arg)
end
Calling it as foo.bar("Hello") prints this:
Hello
nil
However, calling it as foo:bar("Hello") or foo.bar(foo, "Hello") gives you this:
table: 0xDEADBEEF (some hex identifier)
Hello
It's basically the difference between static and member methods in a language like Java, C#, C++, etc.
Using : is more or less like using a this or self reference, and your object (table) does not have a arg1 defined on it (as something like a member). On the other way, using . is just like defining a function or method that is part of the table (maybe a static view if you wish) and then it uses the arg1 that was defined on it.
. defines a static method / member, a static lib, Which means you can't create a new object of it. static methods / libs are just for having some customized functions like printing or download files from the web, clearing memory and...
: Is used for object members, members that are not static. These members change something in an object, for example clearing a specified textbox, deleting an object and...
Metamethod functions(Functions that have :) can be made in lua tables or C/C++ Bindings. a metamethod function is equal to something like this on a non-static object:
function meta:Print()
self:Remove()
end
function meta.Print(self)
self:Remove()
end
Also, with . you can get a number/value that doesn't require any call from a non-static or static object. For example:
-- C:
int a = 0;
-- Lua:
print(ent.a)
-- C:
int a()
{
return 0;
}
-- Lua:
print(ent:a())
same function on a static member would be:
print(entlib.a())
Basically, each non-static object that has a function that can be called will be converted to : for better use.

VB.NET Lambda Does Not Call Method

I'm currently writing a wrapper object for a series of database result sets. In so doing, I've noticed a problem when querying with LINQ and Lambda expressions. Specifically, calling a method within the lambda seems to always make the result set empty and never actually fires the method I'm attempting to filter with. Here's the code:
' Query and filter container results
Public Function [Filter](pFilter As IFilter(Of T)) As System.Linq.IQueryable(Of T)
' THIS YIELDS AN EMPTY SET EVEN WHEN pFilter.Test(o) ALWAYS RETURNS TRUE
Dim lResult As System.Linq.IQueryable(Of T) = mTable.Where(Function(o As T) pFilter.Test(o))
Return lResult
End Function
pFilter implements IFilter with this signature:
Public Interface IFilter(Of T)
Function Test(ByVal pObject As T) As Boolean
End Interface
I've break pointed pFilter.Test(o) and found it is never actually called. Oddly enough, if I replace pFilter.Test(o) with True, I receive the entire table of records as expected. Also, I receive no compile time or run time errors in any case.
I'm pretty new to Lambdas and LINQ so fully recognize I may not understand the limits of what I am attempting to accomplish. Any help is greatly appreciated!
SOLUTION:
I've marked a solution already as the author got me on the right track. The true nature of this problem stems from my attempting to force a .NET function into something LINQ could turn into an SQL statement (which is impossible). To solve this, I've changed my IFilter to return System.Linq.Expressions.Expression(Of Func(Of T, Boolean)) for the Test method. Now I can create strongly-typed filters which return predicates and pass them directly to Where() without the use of a lambda expression. I'm also using LinqKit to make this work more easily for those who may be accomplishing similar tasks.
I think I found what your issue is - understanding the concept of IQueryable. Here is what it says in this article: Lazy Loading With The LazyList
IQueryable is the cornerstone of Linq To Sql, and has (what I think)
is a killer feature: delayed execution. IQueryable essentially creates
an Expression for you that you can treat as an enumerable list - and
only when you iterate or ask for a value will the query be executed.
So you probably never used the result, and that's why it was never called. .NET framework only built the expression tree for you, but did not do any processing.
See also: IQueryable vs. IEnumerable.

How to pass a generic type not having a Interface to a Of T function

I have a following code which works fine
MsgBox(AddSomething(Of String)("Hello", "World"))
Public Function AddSomething(Of T)(ByVal FirstValue As T, ByVal SecondValue As T) As String
Return FirstValue.ToString + SecondValue.ToString
End Function
Now we are redesigning the application to work with parameters of different types which will be provided through XML
<SomeValues>
<Add Param1="Somedata" Param2="SomeData" MyType="String"/>
<Add Param1="Somedata" Param2="SomeData" MyType="MyBusinessObject"/>
</SomeValues>
If I try to provide the following it gives error as Of accepts only type
''''Get DetailsFromXml --- MyType,Param1,Param2
MsgBox(AddSomething(Of Type.GetType(MyType))(Param1,Param2))
How to solve this issue.
Edit
The above example is given to make the question simple. Actual issue is as follows
I am using SCSF of P&P.
Following is per view code which has to be written for each view
Private Sub tsStudentTableMenuClick()
Dim _StudentTableListView As StudentListView
_StudentTableListView = ShowViewInWorkspace(Of StudentListView)("StudentTable List", WorkspaceNames.RightWorkspace)
_StudentTableListView.Show()
End Sub
Now I want to show the views dynamically.
Public Sub ShowModalView(ByVal ViewName As String)
Dim _MasterListView As >>>EmployeeListView<<<<
_MasterListView = ShowViewInWorkspace(Of >>>EmployeeListView<<<)("Employee List", WorkspaceNames.RightWorkspace)
_MasterListView.Show()
End Sub
So the part shown using the arrows above has to be somehow dynamically provided.
The point of generics is to provide extra information at compile-time. You've only got that information at execution-time.
As you're using VB, you may be able to get away with turning Option Strict off to achieve late binding. I don't know whether you can turn it off for just a small piece of code - that would be the ideal, really.
Otherwise, and if you really can't get the information at compile-time, you'll need to call it with reflection - fetch the generic "blueprint" of the method, call MethodInfo.MakeGenericMethod and then invoke it.
I assume that the real method is somewhat more complicated? After all, you can call ToString() on anything...
(It's possible that with .NET 4.0 you'll have more options. You could certainly use dynamic in C# 4.0, and I believe that VB10 will provide the same sort of functionality.)
In .Net generics, you must be able to resolve to a specific type at compile time, so that it can generate appropriate code. Any time you're using reflection, you're resolving the type at run time.
In this case, you're always just calling the .ToString() method. If that's really all your code does, you could just change the parameter type to Object rather than use a generic method. If it's a little more complicated, you could also try requiring your parameters to implement some common interface that you will define.
If all you are doing is ToString, then making the parameters object instead would solve the problem in the simplest way. Otherwise you are going to have to bind the type at run-time, which in C# looks like:
System.Reflection.MethodInfo mi = GetType().GetMethod("AddSomething");
mi = mi.MakeGenericMethod(Type.GetType(MyType));
object result = mi.Invoke(this, new object[] { Param1, Param2 });
Because it involves reflection it won't be fast though... but I assume that's not a problem in this context.

In VB6, how do I call a COM object requiring a pointer to an object?

I'm having trouble with a .NET Assembly that is com visible, and calling certain methods from VB6.
What I have found is that if the parameters are well defined types, (e.g. string), calls work fine. If they are higher level objects, it raises a runtime error '438' suggesting that the property or method is not present. I suspect that this is a question of having the correct signature on the call, but I can't see how to do this correctly.
I believe that I've done everything correct on the .NET side (ComVisible, public interfaces, etc. and even have it down to a simple enough case).
Looking at the output from the typelib viewer, I have the following:
dispinterface ISimple {
properties:
methods:
[id(0x60020000)]
void Add([in] ISimpleMember* member);
[id(0x60020001)]
ISimpleMember* Create();
};
OK. So I have 2 methods in my ISimple interface. One takes an ISimpleMember (Add), whilst the other, returns an ISimpleMember.
The corresponding code in VB looks like this:
Dim item As ISimpleMember
Dim simple As simple
Set item = New SimpleMember
item.S1 = "Hello"
item.S2 = "World"
Set simple = New simple
simple.Add (item) <---- This raised the run time error 438
Set item = simple.Create <---- This works fine, returning me an ISimpleMember
I've tried a couple of things:
1. Dim item as SimpleMember (makes no difference)
2. simple.Add(ObjPtr(item)) - Syntax error
3. simple.Add(ByRef item) - Syntax error
Basically, The run time error is the same as if I had
simple.AMethodThatIHaventWritten()
Also, If I browse References in the VB6 Environment, The Add method is well defined:
Sub Add(member As SimpleMember)
I've found the answer I believe. It was very simple:
When calling a SubRoutine, I shouldn't put the name in braces. the call should have been:
simple.add member
rather than
simple.add(member)
If I change it to a function (i.e. return a value rather than void) the braces are necessary
This seems to work
(Probably) The top 3 VB6 coding mistakes made by devs who now mainly code in C#, Javascript etc. Are:-
Placing ; at the end of lines. Its a syntax error very easily spotted and picked up the compiler.
Not placing Then on the other side of an If condition expression. Again its a syntax error.
Calling a method without retrieving a value and yet using ( ) to enclose the parameter list. With multiple parameters this is a syntax error and easily found. With only one parameter the use of ( ) is interpreted as an expression. Its the result of the ( ) expression which is passed as parameter. This causes problems when ByRef is expected by the callee.