Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
210 views
in Technique[技术] by (71.8m points)

c# - Is there a way to dynamically execute a string in .net, similar to eval() in javascript or dynamic sql in sql?

Is there a way to dynamically execute code contained in a string using .net 2.0, in a similar way to eval() in javascript or using sp_executeSQL in tsql?

I have a string value in a variable that I want to manipulate at some point in my application - so the code would essentially be string manipulation. I don't know what different manipulations will be needed so i'd like them to be configurable.

I don't really care what language the dynamic code is written in, whatever is easiest to implement and simple enough to write.

For example I might want to replace instances of '.' character with '-', or strip out all spaces, or similar. If I was doing this in sql I'd use dynamic sql, but I want to execute it in .net code, something like this:

// Get the value to be manipulated
string s = ... // wherever s comes from

// Get the manipulation code, eg this might come from a database 
// setting that can be changed without recompiling the .net code.
string manipulation = Settings.GetSomeValue("ManipulationSetting");

// This is what I want to know how to do: apply some manipulation to the string.
string result = MagicDynamicEvalClass.Eval(manipulation, s);

// Now I would do stuff with the result.

I could possibly just use regex find/replace expressions. Since all i'm doing is string manipulation this should be sufficient provided I can write clever enough regular expressions. eg:

// Get the value to be manipulated
string s = ... // wherever s comes from

// Get the code to use to manipulate s, eg this might come from a database 
// setting that can be changed without recompiling the .net code.
string findRegex = Settings.GetSomeValue("RegexPattern");
string replaceRegex = Settings.GetSomeValue("RegexReplace");

// This is what I want to know how to do: apply some manipulation to the string.
string result = Regex.Replace(s, findRegex, replaceRegex);

// Now I can do stuff with the result.

But in some cases my manipulation requirement might exceed what's possible with regex, or I might want to apply multiple steps, eg replace '.' with '-' and also strip spaces. Perhaps I could store a list of find/replace regexes and iterate over them... but anyone have a better suggestion?

UPDATE - example using dynamic sql

I don't want a solution that requires me to know in advance what manipulations are possible, and I'm really looking for something simple. eg in sql I'd do something like this:

declare @s nvarchar(1000)
declare @manipulation nvarchar(1000)
declare @result nvarchar(1000)

-- ... Get the values from wherever they come from

-- Execute the manipulation dynamically
EXEC sp_ExecuteSQL @stmt = @manipulation
    , @params = N'@s nvarchar(1000), @result nvarchar(1000) OUTPUT'
    , @s = @s, @result = @result OUTPUT

Then I could put arbitrary sql into my @manipulation, something like this SET @result = REPLACE( REPLACE( @s, '.', '-'), ' ', '' )

Yes, this would require me to be careful about what values are allowed to be put into @manipulation, but it would give me the flexibility I need in future.

A similar approach would be possible in javascript I guess, using eval().

UPDATE - example using MSScript control from .net:

This seems like a possible approach, although perhaps overkill for the simple case I want to deal with. It uses the Microsoft Script Control library to allow execution of arbitrary VBScript.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not tooo hard ;) I put together a little example. This should help you decide if you want to use dynamic scripts.. or regexes.

What you can do is create an interface in your assembly, which your dynamic code will implement:

namespace CompileScriptExample
{
  public interface IStringManipulator
  {
    string processString(string aString);
  }
}

Then create a ScriptRunner class:

namespace CompileScriptExample
{ 
public class ScriptRunner
{

    public static string RunScript(string scriptCode, string scriptParameter)
    {

        CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider();

        //configure parameters
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = false;
        parameters.GenerateInMemory = true;
        parameters.IncludeDebugInformation = false;
        string reference;
        // Set reference to current assembly - this reference is a hack for the example..
        reference = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        parameters.ReferencedAssemblies.Add(reference+"\CompileScriptExample.exe");

        //compile
        CompilerResults results = provider.CompileAssemblyFromSource(parameters, new string[] { scriptCode });

        if (results.Errors.Count == 0)
        {
            IStringManipulator compiledScript=(IStringManipulator)FindInterface(results.CompiledAssembly, "IStringManipulator");
            return compiledScript.processString(scriptParameter);//run the script, pass the string param..
        }
        else
        {
            foreach(CompilerError anError in results.Errors)
            {
                MessageBox.Show(anError.ErrorText);
            }
            //handle compilation errors here
            //..use results.errors collection
            throw new Exception("Compilation error...");
        }
    }

    private static object FindInterface(Assembly anAssembly, string interfaceName)
    {
        // find our interface type..
        foreach (Type aType in anAssembly.GetTypes())
        {
            if (aType.GetInterface(interfaceName, true) != null)
                return anAssembly.CreateInstance(aType.FullName);
        }
        return null;
    }
}

}

Now all you have to do is create a script string with code that implements your interface like..

string myScriptString=@"using CompileScriptExample;
public class MyStringManipulator : IStringManipulator
{
  public string processString(string aString)
  {
        return aString+aString;
  }
};

and then.. in your code, make use of the ScriptRunner to process your string with your dynamic code:

string processedString = ScriptRunner.RunScript(myScriptString, "hello");

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...