TheSwamp
Code Red => .NET => Topic started by: Peter Jamtgaard on May 26, 2010, 12:10:46 PM
-
Hi Group,
I want to pass a string to a vb.net sub and have it convert the string to a vb.net expression and then evaluate it
Like the vbastmt in AutoCAD
Like this LISP expression: (eval (read "(setq x 1)"))
It reads (converts) the string to an expression and then evaluates it.
Thanks
-
There is no equivalent in .NET. In fact, if you really think about it, that concept doesn’t relate to .NET and OOP.
You have properties and methods that you can ‘get to’ with strings using Reflection. Other than that, your question does not give enough information on what you are trying to accomplish to provide any other help.
-
how about C#? .. C# Script Engine http://www.csscript.net/ && http://www.codeproject.com/KB/cs/cs-script_for_cp.aspx
-
Hey Ken,
Other than that, your question does not give enough information on what you are trying to accomplish to provide any other help.
Let me try to elaborate.
Say if I were to run the vbastmt command in AutoCAD (when vba is available) and I were to pass the function this string:
msgbox(thisdrawing.name)
A message box would appear and say "Drawing1.dwg" for example...
The statement is a string.
The string is converted to a vba expression and then evaluated (run)
I want to know if there is a way to do the same thing with vb.net.
I pass a vb.net expression as a string argument to some (unknown vb.net expression), and it converts the string to an vb.net expression and evaluates it.
More sense?
Peter
-
Here's an article I found with a quick Google search Pete.
http://www.eggheadcafe.com/articles/20030908.asp
I 'think' I know where you're headed with this. Let us know how it turns out.
-
Very interesting...
:-o
Peter
-
OOOH .. I can see lots of neat thingies for that little gem ...
can we say code validation without compiling the entire thing .... select a piece of complex code, run it through the evaluator and see if the returned object is what is expected ... on the fly ...
yep ... I gotta keep this puppy
-
I'm not so sure about that... It looks like it basically compiles and netloads the assembly that is created "on the fly", which indicates we'd have all the usual problems with the inability to unload an assembly once it is loaded... It also seems very "heavy handed"... I'm not sure what sort of impact this approach might have, once the application has been running for a while.
-
why couldn't you netload the assembly, the assembly would then netload the code in a wrapper (we should be able to capture the wrapper and use it to unload it) then simpley use is as expected .. certainly you wouldn't use it while actually using AutoCAD .. it would be a testing environment at best ..
besides, lately I have been doing a heap of stuff that isn't cad related .. data crunching, database programming, GIS calculations and statistical analysis software ... I can see this being useful right in the IDE if developed properly ...
-
This is a really interesting discussion.
(I would be interested in the disposable wrapper for the loading of a net application you mentioned to unload the app.)
I had hoped that it would be fairly straight forward to evaluate a vb.net statement inside .net.
Another question, I want to demand load vb.net dll's and avoid the netload command pipe.
Would that example provide a way to do that or do one of you have an example of a routine that does that?
Peter
-
Hey Group,
In ther example above I noticed the CodeDOM include.
I did a web search on it and found this example over on the vbforums.
http://www.vbforums.com/showthread.php?t=397265
By Conipto.
It works pretty good and evaluates VB statements.
I am not sure if it eveluates VB.net statements.
Any thoughts would be greatly appreciated?
Peter
Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic 'More than just VB6 Runtime functions in here!
Imports System.Reflection
And here is the function, converted to VB.NET
VB Code:
''' <summary>
''' A simple function using CodeDom to process an expression.
''' </summary>
''' <param name="command">A string expression to evaluate</param>
''' <returns>A double with the result of the evaluated command parameter</returns>
''' <remarks>Vulnerable to injection attacks.</remarks>
Private Function ProcessCommand(ByVal command As String) As Double
Dim MyProvider As New VBCodeProvider 'Create a new VB Code Compiler
Dim cp As New CompilerParameters 'Create a new Compiler parameter object.
cp.GenerateExecutable = False 'Don't create an object on disk
cp.GenerateInMemory = True 'But do create one in memory.
'If cp.OutputAssembly is used with a VBCodeProvider, it seems to want to read before it is executed.
'See C# CodeBank example for explanation of why it was used.
'the below is an empty VB.NET Project with a function that simply returns the value of our command parameter.
Dim TempModuleSource As String = "Imports System" & Environment.NewLine & _
"Namespace ns " & Environment.NewLine & _
"Public Class class1" & Environment.NewLine & _
"Public Shared Function Evaluate()" & Environment.NewLine & _
"Return " & command & Environment.NewLine & _
"End Function" & Environment.NewLine & _
"End Class" & Environment.NewLine & _
"End Namespace"
'Create a compiler output results object and compile the source code.
Dim cr As CompilerResults = MyProvider.CompileAssemblyFromSource(cp, TempModuleSource)
If cr.Errors.Count > 0 Then
'If the expression passed is invalid or "", the compiler will generate errors.
Throw New ArgumentOutOfRangeException("Invalid Expression - please use something VB could evaluate")
Else
'Find our Evaluate method.
Dim methInfo As MethodInfo = cr.CompiledAssembly.GetType("ns.class1").GetMethod("Evaluate")
'Invoke it on nothing, so that we can get the return value
Return Convert.ToDouble(methInfo.Invoke(Nothing, Nothing))
End If
End Function
Sample usage and output:
VB Code:
MsgBox(ProcessCommand(TextBox1.Text)) 'SHows a message box with the result of an expression in TextBox1
Console.WriteLine(ProcessCommand("1+1").ToString()) 'Displays 2
Console.WriteLine(ProcessCommand("Math.PI").ToString()) 'Displays 3.14159265358979
Console.WriteLine(ProcessCommand("Math.Abs(-22)").ToString()) 'Displays 22
Console.WriteLine(ProcessCommand("3-4+6+7+22/3+66*(55)").ToString()) 'Displays 3649.333333333333333333
-
http://www.codeproject.com/KB/recipes/expressionevaluator.aspx
-
.NET doesn't provide an eval, but you can invoke vbscript:
http://www.devx.com/vb2themax/Tip/18773
http://weblogs.asp.net/rosherove/art...scripting.aspx
So following the example shown here
http://through-the-interface.typepad...g_started.html
In Visual Studio VB.NET:
- create a project called VBMgdAcad1
- add a reference to the COM Microsoft Script Control
- then compile this VB.NET code :
Imports Autodesk.AutoCAD.Runtime
PublicClass CIMMClass
' Define command 'Asdkcmd1'
<CommandMethod("Asdkcmd1")> _
PublicSub Asdkcmd1()
MsgBox("Hello!" + myEval("12 + 3 * 10"))
EndSub
PublicFunction myEval(ByVal expr AsString) AsString
Dim sc AsNew MSScriptControl.ScriptControl()
sc.Language = "VBScript"
myEval = sc.Eval(expr)
EndFunction
EndClass
In ACAD:
- NETLOAD VBMgdAcad1.dll
- Issue Asdkcmd1 at ACAD's command prompt
to see Hello!42 in a messagebox.
hth
Hugh Adamson
www.hatchkit.com.au
-
Sorry, the above broken links should be
http://weblogs.asp.net/rosherove/articles/dotnetscripting.aspx
and
http://through-the-interface.typepad.com/through_the_interface/2006/07/getting_started.html
-
the assembly would then netload the code in a wrapper (we should be able to capture the wrapper and use it to unload it)
Keith,
Do you have an example or can you direct me or to an example where a routine captures a wrapper and uses it to unload it?
That would be REALLY useful.
Having a netunload expression would be good.
Peter
-
I don't have an example, but theoretically it should be possible. Presuming the wrapper is a predefined function that merely holds the code.
If you always use the same wrapper name you can always unload that wrapper function could you not?
-
Keith,
I have been playing with an alternate to the netload command line command.
I am interested in capturing the wrapper, as I mentioned.
Is this a good place to start or should I use that something similar to the
code shown on eggheadcafe referenced above?
Peter
<LispFunction("Netload")> _
Public Function Netload(ByVal rbfNetAssemblyFile As ResultBuffer) As ResultBuffer
Dim rbfReturn As New ResultBuffer
Try
Dim arrNetAssemblyFile As TypedValue() = rbfNetAssemblyFile.AsArray()
System.Reflection.Assembly.LoadFrom(arrNetAssemblyFile(0).Value.ToString)
return Nothing
Catch
rbfReturn.Add(New TypedValue(&H138D, "Catch Error"))
Return rbfReturn
End Try
End Function
-
After revisiting the code at eggheadcafe, you will note that is writes the class on the fly and then compiles it and executes the function EvalCode The wrapper itself would necessarily have to be the evaluator. You could netload the evaluator and send it the string to evaluate, but it won't help you in the IDE. Presumably you want to execute .Net functions in lisp (as evidenced by your function above).
Why build your function around the code provided, netload it, and pass to it the string needed to be evaluated. Presumably the arbitrary class would be self depreciating when the class is disposed, thus unloading it wouldn't be necessary. It would require some testing to be sure, but based on what I've seen, it could be really cool to introduce some .net functionality to lisp.
When I get time, I think I will look into this a bit more.
-
@ Peter
you should test arguments to see if they are null
you should return true on success and nil on error. the way you have it now, you're returning nil on success and a list on failure.
IMO, When interacting with lisp, you should try you make your functions behave as a lisp function would
-
something like this
// going to return nil or 1, I think one of the
// cad versions had a bug with with T
[LispFunction("LOADNET")]
public static object LoadNetModule(ResultBuffer args)
{
try
{
if(args == null ) return null;
TypedValue[] tvs = args.AsArray();
if (tvs.Length == 0) return null;
TypedValue arg = tvs[0];
if (arg.TypeCode != (int)LispDataType.Text) return null;
string file = arg.Value as string;
if (string.IsNullOrEmpty(file)) return null;
System.Reflection.Assembly.LoadFrom(file);
return 1;
}
catch
{
return null;
}
}
-
ok, I'll play ...
How do you load that after it's compiled into an assembly ??
;-)
-
ok, I'll play ...
How do you load that after it's compiled into an assembly ??
;-)
Sorry, I should have posted in this thread
http://www.theswamp.org/index.php?topic=33538.0
-
ok, I'll play ...
How do you load that after it's compiled into an assembly ??
;-)
Sorry, I should have posted in this thread
http://www.theswamp.org/index.php?topic=33538.0
OK, no hassles ..
but somewhere you'd still need a NETLOAD, yes ??
.. and I don't see a problem with using netload, but perhaps I've missed some part of the discussion.
-
ok, I'll play ...
How do you load that after it's compiled into an assembly ??
;-)
Sorry, I should have posted in this thread
http://www.theswamp.org/index.php?topic=33538.0
.... I've missed some part of the discussion....
I think that was me, I'll go back an play in my ARX sinkhole :laugh:
-
oh yeah, that's right ... take your ball and run away and play with Paul :-D
-
footnote:
If [you] paid attention to the API wishlist @ http://through-the-interface.typepad.com/through_the_interface/2010/05/theres-still-time-to-fill-out-the-2010-api-wishlist-surveys.html
you'll notice that C# scripting (as well as an enhanced VLIDE) is scoring high on the voting.
... though we'll need to wait to see what action is taken regarding the items on the list.
further footnote :
Peter, how'd you go with your submission for a course at AU this year ??
-
It would require some testing to be sure, but based on what I've seen, it could be really cool to introduce some .net functionality to lisp.
How funny. I wouldn't use the word "cool" to describe Lisp.Net... Maybe "cringe-worthy"... Or maybe just "ugh"... :-)
-
I suppose its a good thing that you don't make all the rules ... or that any one person doesn't .. it would be a pretty dull place to live
-
I think L# would have been really cool especially with .NET4, too bad it's not being maintained.
-
I suppose its a good thing that you don't make all the rules ... or that any one person doesn't .. it would be a pretty dull place to live
Sometimes I really wonder about the posts I read here... Some of them get pretty far out there.
-
I suppose its a good thing that you don't make all the rules ... or that any one person doesn't .. it would be a pretty dull place to live
Sometimes I really wonder about the posts I read here... Some of them get pretty far out there.
Well, wonder no more ... would you like to be appointed the one and only rule maker? ;-)
-
Group,
I sure enjoy the dialog when it comes to LISP, there are a lot of strong emotions running.
LISP is cool, so are the other languages...IMHO, its all good.
My lecture proposal is still pending.
It is a LOT of work to write it up and present it.
For the small stipend...
What is important is that I learn how to do it and then share what I learn with everyone...somehow.
Peter
-
Here's an article I found with a quick Google search Pete.
http://www.eggheadcafe.com/articles/20030908.asp
I 'think' I know where you're headed with this. Let us know how it turns out.
I got this one to work
(EvaluateVB "MsgBox (\"Hello World\")")
It does create a unknown assembly so will eat up memory.
But it works for a compile at runtime function. You can also import a file.vb file too if you play with a couple methods.
A certain expert I corresponded with regarding this function said.
"Compiler as a Service is going to be a key feature in .NET 5"
so something like this will be available in a couple years without the baggage.
I thought that was good news.
Peter
It is a modified form of the original code on eggheadcafe that was recommended by Bobby C. Jones See link above.
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.Runtime
Imports Microsoft.VisualBasic
Imports System
Imports System.Text
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.IO
Public Class EvaluatorVBClass
' Syntax (EvaluateVB "MsgBox (\"Hello World\")")
<LispFunction("EvaluateVB")> _
Public Function EvaluateVB(ByVal rbfLISPArguments As ResultBuffer) As TypedValue
Dim arrLISPArguments As TypedValue() = rbfLISPArguments.AsArray
Dim objReturn As Object = Evaluate(arrLISPArguments(0).Value.ToString)
If Not objReturn = Nothing Then
Select Case (objReturn.GetType.ToString)
Case "System.Int16"
Return New TypedValue(5003, objReturn)
Case "System.Int32"
Return New TypedValue(5010, objReturn)
Case "System.String"
Return New TypedValue(5005, objReturn)
Case "System.Double"
Return New TypedValue(5001, objReturn)
End Select
End If
Return New TypedValue(5019, -1)
End Function
Public Function Evaluate(ByVal vbCode As String) As Object
'Dim objVBCodeProvider As VBCodeProvider = New VBCodeProvider
Dim objCodeDomProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VisualBasic")
Dim objCompilerParameters As CompilerParameters = New CompilerParameters()
objCompilerParameters.GenerateInMemory = True
' objCompilerParameters.OutputAssembly = "C:\Documents and Settings\peter.CORDECKSALES\My Documents\Visual Studio 2008\Projects\Evaluation\EvaluateVB\EvaluateVB\bin\Debug\testeval.dll"
objCompilerParameters.ReferencedAssemblies.Add("system.dll")
'objCompilerParameters.ReferencedAssemblies.Add("c:\yourProjectDir\bin\YourBaseClass.dll")
objCompilerParameters.CompilerOptions = "/t:library"
Dim objStringBuilder As StringBuilder = New StringBuilder("")
objStringBuilder.Append("Imports System" & vbCrLf)
objStringBuilder.Append("Imports Microsoft.VisualBasic" & vbCrLf)
objStringBuilder.Append("Namespace Code " & vbCrLf)
objStringBuilder.Append("Class Library " & vbCrLf)
objStringBuilder.Append("public function EvalCode() as Object " & vbCrLf)
'objStringBuilder.Append("Dim objResult as Object " & vbCrLf)
'sb.Append("YourNamespace.YourBaseClass thisObject = New YourNamespace.YourBaseClass()")
objStringBuilder.Append("Dim objResult as Object = " & vbCode & vbCrLf)
objStringBuilder.Append("Return objResult" & vbCrLf)
objStringBuilder.Append("End Function " & vbCrLf)
objStringBuilder.Append("End Class " & vbCrLf)
objStringBuilder.Append("End Namespace" & vbCrLf)
Dim objCompilerResults As CompilerResults
'
objCompilerResults = _
objCodeDomProvider.CompileAssemblyFromSource(objCompilerParameters, objStringBuilder.ToString())
If objCompilerResults.Errors.Count > 0 Then
' Display compilation errors.
Dim objCompilerError As CompilerError
For Each objCompilerError In objCompilerResults.Errors
MsgBox(objCompilerError.ToString())
Next objCompilerError
Else
Dim objAssembly As System.Reflection.Assembly = objCompilerResults.CompiledAssembly
Dim objInstance As Object = objAssembly.CreateInstance("Code.Library")
Dim objType As Type = objInstance.GetType()
Dim objMethodInfo As MethodInfo = objType.GetMethod("EvalCode")
Return objMethodInfo.Invoke(objInstance, Nothing)
End If
Return Nothing
End Function
End Class__________________