Thread View: alt.pl.comp.lang.csharp
5 messages
5 total messages
Started by qaz
Mon, 20 Sep 2010 08:56
jak to sie robi w C# ?
Author: qaz
Date: Mon, 20 Sep 2010 08:56
Date: Mon, 20 Sep 2010 08:56
9 lines
1399 bytes
1399 bytes
Mam stringa z formuła np. sFromula = " iIle * dNorma * dCena * (1 + dWsp) "
gdzie ile, dNorma, dCena dWsp są zmiennymi
formuły są wczytywane z tabeli bazy danych (mogą zawierać cztery podstawowe
działania, maksymalna długość formuły jest ustawiona na 50 znaków)
Jak w C# najlepiej wykonać zawarte w sFormula działanie arytmetyczne ?
--
pzdr
qaz
Re: jak to sie robi w C# ?
Author: Selvin
Date: Mon, 20 Sep 2010 15:00
Date: Mon, 20 Sep 2010 15:00
95 lines
4096 bytes
4096 bytes
1. Uzycie jakiegos języka skryptowego(np IronPython)
2. Napisanie wlasnego parsera wyrazen.
3. w frameworku 4 mozna np tak:
namespace ScriptingInterface
{
public interface IScriptType
{
dynamic RunScript(dynamic _);
}
public class ScriptProvider
{
ScriptProvider(string code)
{
Assembly compiledScript = CompileCode(@"
using System;
using ScriptingInterface;
using System.ComponentModel.Composition;
[Export(typeof(IScriptType))]
public class ScriptType : IScriptType
{
public dynamic RunScript(dynamic _)
{
return " + code + @";
}
}");
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new
AssemblyCatalog( compiledScript));
CompositionContainer _container = new
CompositionContainer(catalog);
_container.SatisfyImportsOnce(this);
}
static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new
Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add("System.Core.dll");
options.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
options.ReferencedAssemblies.Add("System.ComponentModel.Composition.dll");
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
CompilerResults result;
result = csProvider.CompileAssemblyFromSource(options,
code);
if (result.Errors.HasErrors)
{
throw new Exception(result.Errors[0].ErrorText);
}
return result.CompiledAssembly;
}
[Import]
IScriptType Script { get; set; }
public static dynamic RunScript(string code, dynamic param)
{
return new
ScriptingInterface.ScriptProvider(code).Script.RunScript(param);
}
}
}
i wywolanie
private void button1_Click(object sender, EventArgs e)
{
dynamic param = new ExpandoObject();
param.iIle = 2;
param.dNorma = 2.55M;
param.dCena = 120.57M;
param.dWsp = 0.2M;
try
{
MessageBox.Show(ScriptingInterface.ScriptProvider.RunScript(textBox1.Text,
param).ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
mankamentem tego rozwiazania jest to ze wyrazenie musi wygladac tak:
_.iIle * _.dNorma * _.dCena * (1 + _.dWsp)
Re: jak to sie robi w C# ?
Author: Selvin
Date: Mon, 20 Sep 2010 16:04
Date: Mon, 20 Sep 2010 16:04
79 lines
3933 bytes
3933 bytes
jeszcze inne wywolanie:
private void button1_Click(object sender, EventArgs e)
{
var csb = new SqlConnectionStringBuilder();
csb.IntegratedSecurity = true;
csb.DataSource = "BAZA2005";
using (var con = new SqlConnection(csb.ConnectionString))
{
con.Open();
var cmd = new SqlCommand("SELECT 2 iIle, 2.55 dNorma,
120.57 dCena, 0.2 dWsp, '_.iIle * _.dNorma * _.dCena * (1 + _.dWsp) *
100' sFormula", con);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
dynamic param = new DynamicDataRow(reader);
//dynamic param = new ExpandoObject();
//param.iIle = 2;
//param.dNorma = 2.55M;
//param.dCena = 120.57M;
//param.dWsp = 0.2M;
try
{
//
MessageBox.Show(ScriptingInterface.ScriptProvider.RunScript(textBox1.Text,
param).ToString());
MessageBox.Show(ScriptingInterface.ScriptProvider.RunScript(param.sFormula,
param).ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
a tak np zamieniamy sobie IDataRecord na dynamic
public class DynamicDataRow : DynamicObject
{
Dictionary<string, object> record_ = new Dictionary<string,
object>();
public DynamicDataRow(IDataRecord record)
{
for (int i = 0; i < record.FieldCount; i++)
record_[record.GetName(i)] = record[i];
}
public override bool TryGetMember(GetMemberBinder binder, out
object result)
{
return record_.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder,
object value)
{
record_[binder.Name] = value;
return true;
}
}
mozna jeszcze dodac cachowanie skryptu
static Dictionary<string, IScriptType> scriptcache = new
Dictionary<string, IScriptType>();
public static dynamic RunScript(string code, dynamic param)
{
if (!scriptcache.ContainsKey(code))
scriptcache[code] = new
ScriptingInterface.ScriptProvider(code).Script;
return scriptcache[code].RunScript(param);
}
Re: jak to sie robi w C# ?
Author: Selvin
Date: Mon, 20 Sep 2010 22:38
Date: Mon, 20 Sep 2010 22:38
130 lines
6701 bytes
6701 bytes
ciach z nudow pobawilem sie jeszcze:
1. wywalilem MEF(byl tylko po to by nie bawic sie Reflection)
2. w teorii (http://bloggingabout.net/blogs/vagif/archive/2010/04/02/
don-t-use-activator-createinstance-or-constructorinfo-invoke-use-
compiled-lambda-expressions.aspx) (i tam jest o konstruktorach,
ale ...) uzylem skompilowanego wyrazenia lambda a nie MethodInfo
Invoke (przy duzej ilosci odwolan do tego samego skryptu compilacja
powinna sie zwrocic, zreszta ... nie ma co optymalizowac na sile
trzeba zrobic testy na prawdziwych danych)
3. Exception o nie udanej kompilacji zwraca teraz blad opis i numer
kolumny w ktorej blad wystapil
4. do wysylanego parametru mozna dodac spokojnie funkcje przyklad:
MojaFunkcjaDoPodwajania
5. przyklad wywolania funkcji systemowych (DateTime.Now)
6. zmienilem klase opakowujaca IDataRecord teraz zamias wlasnej klasy
mamy po prostu obiekt typu ExpandoObject uzyskany przez uzycie
rozszerzenia do IDataRecord o nazwie AsDynamic
public static class ScriptProvider
{
static Regex expr = new Regex("\\s+",
System.Text.RegularExpressions.RegexOptions.Compiled);
static Dictionary<string, Func<dynamic, dynamic>> scriptscache =
new Dictionary<string, Func<dynamic, dynamic>>();
const string body = @"using System;public class ScriptType{{public
static object RunScript(dynamic _){{return {0} ;}}}}";
static int codebegin = body.IndexOf("{0}") - 2;
static Microsoft.CSharp.CSharpCodeProvider csProvider = new
Microsoft.CSharp.CSharpCodeProvider();
static CompilerParameters options = new CompilerParameters();
static ParameterExpression param =
Expression.Parameter(typeof(object), "param");
static ScriptProvider()
{
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add("System.Core.dll");
options.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
}
static Func<dynamic, dynamic> CreateScript(string code)
{
code = expr.Replace(code, string.Empty);
if (!scriptscache.ContainsKey(code))
{
CompilerResults result =
csProvider.CompileAssemblyFromSource(options, string.Format(body,
code));
if (result.Errors.HasErrors)
{
throw new Exception(string.Join(Environment.NewLine,
result.Errors.Cast<CompilerError>().Select(x => string.Format("({1},
{2}), error {3}: {0}", x.ErrorText, x.Line, x.Column - codebegin,
x.ErrorNumber)).ToArray()));
}
scriptscache[code] = (Func<dynamic,
object>)Expression.Lambda(typeof(Func<dynamic, object>),
Expression.Call(result.CompiledAssembly.GetType("ScriptType").GetMethod("RunScript"),
param), param).Compile();
}
return scriptscache[code];
}
public static object RunScript(string code, dynamic param)
{ return CreateScript(code)(param); }
public static T RunScript<T>(string code, dynamic param) { return
(T)CreateScript(code)(param); }
public static Func<dynamic, object> GetScriptAsFunction(string
code) { return CreateScript(code); }
}
public static class DataRecordExtensions
{
public static dynamic AsDynamic(this IDataRecord record)
{
ExpandoObject ret = new ExpandoObject();
IDictionary<string, object> dic = ret as IDictionary<string,
object>;
for (int i = 0; i < record.FieldCount; i++)
dic[record.GetName(i)] = record[i];
return ret;
}
}
private void button1_Click(object sender, EventArgs e)
{
var csb = new SqlConnectionStringBuilder();
csb.IntegratedSecurity = true;
csb.DataSource = ".\\SQLEXPRESS";
using (var con = new SqlConnection(csb.ConnectionString))
{
con.Open();
var cmd = new SqlCommand(@"SELECT 2.0 iIle, 2.55
dNorma, 120.57 dCena, 0.2 dWsp, '_.iIle * _.dNorma * _.dCena * (1 -
_.dWsp)' sFormula
UNION ALL
SELECT 2, 2.55, 120.57, 0.21, '_.iIle * _.dNorma
* _.dCena * (1 - _.dWsp)'
UNION ALL
SELECT 2, 2.55, 120.57, 0.21,
'_.MojaFunkcjaDoPodwajania(_.iIle*_.dNorma*_.dCena*(1-_.dWsp))'
UNION ALL
SELECT 2 , 2 , 120 , 0 , 'DateTime.Now.Day* _.iIle*
_.dNorma * _.dCena * (1 - _.dWsp)'", con);
//ostatnia funkcje uzaleznilismy takze od dnia
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
dynamic param = reader.AsDynamic();
// a co tam dodamy swoja funkcje
param.MojaFunkcjaDoPodwajania = new
Func<dynamic, object>(x => 2 * x);
try
{
var result =
ScriptProvider.RunScript<decimal>(param.sFormula, param);
MessageBox.Show(string.Format("{0} = >
{1}", param.sFormula, result));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
Re: jak to sie robi w C# ?
Author: qaz
Date: Tue, 21 Sep 2010 07:32
Date: Tue, 21 Sep 2010 07:32
18 lines
2042 bytes
2042 bytes
Użytkownik "Selvin" <przemek.sulikowski@gmail.com> napisał w wiadomości
news:586ce832-b369-4b9c-93f8-789982488be4@j5g2000vbg.googlegroups.com...
>ciach z nudow pobawilem sie jeszcze:
Dzięki
Trochę mnie przeraziłeś stopniem skomplikowania - a nie wiem, czy zwróciłeś
uwagę, że formuła odczytywana jest z tabeli i może zawierać inne (nie znane
mi w tym momencie) parametry.
Muszę przekopać całą koncepcję (może da się uniknąć zapisywania formuł w
postaci działań do wykonania, wydaje się, że jedynym działaniem będzie
mnożenie)
Kiedyś pisałem w VFoxPro a tam można było zrobić tak:
wynik = &(iIle * dNorma * dCena * (1 + dWsp) ) czy cokolwiek innego, byle
zmienne/parametry były wcześniej ustawione
--
pzdr
qaz
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads