Printing out expression code and value - c#

Is it possible to implement printing out expression code and value given an expression code as string?
class MyClass
{
// Expected output
// 2 + 2 = 4
// v = 3
// Field = 5
// OtherClass.GetInfo() = Hello
// new OtherClass().OtherField = 22
//
void MyMethod()
{
Console.WriteLine(ExpressionPrintString("2 + 2"));
int v = 3;
Console.WriteLine(ExpressionPrintString("v"));
Console.WriteLine(ExpressionPrintString("Field"));
Console.WriteLine(ExpressionPrintString("OtherClass.GetInfo()"));
Console.WriteLine(ExpressionPrintString("new OtherClass().OtherField"));
}
int Field = 5;
}
class OtherClass
{
public static sting GetInfo() { return "Hello"; }
public int OtherField = 22;
}
I am aware of that Expression<TDelegate> allows to do it for Lambda expressions, like this:
// Usage: ExpressionPrintString(() => 2 + 2) // returns "2 + 2 = 4"
static string ExpressionPrintString(Expression<Func<object>> expr, string delimiter = " = ")
{
return expr.ToString().Replace("() => ","")
+ delimiter
+ expr.Compile().DynamicInvoke();
}
but its output is sometimes not pretty, because it returns the internal representation of the expression. For example
protected override void OnPreRenderComplete(EventArgs e)
{
// In this context
// The following call:
string s = ExpressionPrintString(() => Context.Items["UrlRewrite:OriginalUrl"]);
// returned:
// value(ASP.default_aspx).Context.Items.get_Item("UrlRewrite:OriginalUrl") = http://localhost:8011/Companies
// The expected output would be
// Context.Items["UrlRewrite:OriginalUrl"] = http://localhost:8011/Companies
}

Related

WriteLine both expression and the resulting value?

I often need to log or write values of expression and also something that gives context to that. So for example:
WriteLine($"_managedHandlePtr:{_managedHandlePtr}");
WriteLine($"metadata.GetNative(_ptr, handle):{metadata.GetNative(_ptr, handle)}");
Is it possible to get the original expression from an interpolated string? Something like the below in concept. It would be nice if I could eliminate the stringly part of this but get the same output:
LogExpression($"{_managedHandlePtr}");
LogExprsssion($"{metadata.GetNative(_ptr, handle)}");
// Writes the non-interpolated string expression, a colon, then the evaluated string
void LogExpression(FormattableString formattableString)
{
Console.WriteLine(${formattableString.GetExpression()}:{formattableString.ToString()});
}
Output:
_managedHandlePtr:213456
metadata.GetNative(_ptr, handle):0xG5DcS4
It would also be fine if it had to include the notation from the original string:
{_managedHandlePtr}:213456
I don't think you can get much more than the types of the arguments of the FormtableString.
static class Program
{
static void Main(string[] args)
{
Number a = new Number(1.0); // 1.0
Percent b = new Percent(2.0); // 2%
double c = a + b;
Console.WriteLine(Format($"{a} + {b} = {c}"));
// Number + Percent = Double : 1 + 2% = 1.02
}
static string Format(this FormattableString expression, CultureInfo info = null)
{
if (info == null)
{
info = CultureInfo.InvariantCulture;
}
object[] names = expression.GetArguments().Select((arg) => arg.GetType().Name).ToArray();
return $"{string.Format(expression.Format, names)} : {expression.ToString(info)}";
}
}

How to parse nested parenthesis only in first level in C#

I would like to write C# code that parses nested parenthesis to array elements, but only on first level. An example is needed for sure:
I want this string:
"(example (to (parsing nested paren) but) (first lvl only))"
tp be parsed into:
["example", "(to (parsing nested paren) but)", "(first lvl only)"]
I was thinking about using regex but can't figure out how to properly use them without implementing this behaviour from scratch.
In the case of malformed inputs I would like to return an empty array, or an array ["error"]
I developed a parser for your example. I also checked some other examples which you can see in the code.
using System;
using System.Collections;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string str = "(example (to (parsing nested paren) but) (first lvl only))"; // => [example , (to (parsing nested paren) but) , (first lvl only)]
//string str = "(first)(second)(third)"; // => [first , second , third]
//string str = "(first(second)third)"; // => [first , (second) , third]
//string str = "(first(second)(third)fourth)"; // => [first , (second) , (third) , fourth]
//string str = "(first((second)(third))fourth)"; // => [first , ((second)(third)) , fourth]
//string str = "just Text"; // => [ERROR]
//string str = "start with Text (first , second)"; // => [ERROR]
//string str = "(first , second) end with text"; // => [ERROR]
//string str = ""; // => [ERROR]
//string str = "("; // => [ERROR]
//string str = "(first()(second)(third))fourth)"; // => [ERROR]
//string str = "(((extra close pareanthese))))"; // => [ERROR]
var res = Parser.parse(str);
showRes(res);
}
static void showRes(ArrayList res)
{
var strings = res.ToArray();
var theString = string.Join(" , ", strings);
Console.WriteLine("[" + theString + "]");
}
}
public class Parser
{
static Dictionary<TokenType, TokenType> getRules()
{
var rules = new Dictionary<TokenType, TokenType>();
rules.Add(TokenType.OPEN_PARENTHESE, TokenType.START | TokenType.OPEN_PARENTHESE | TokenType.CLOSE_PARENTHESE | TokenType.SIMPLE_TEXT);
rules.Add(TokenType.CLOSE_PARENTHESE, TokenType.SIMPLE_TEXT | TokenType.CLOSE_PARENTHESE);
rules.Add(TokenType.SIMPLE_TEXT, TokenType.SIMPLE_TEXT | TokenType.CLOSE_PARENTHESE | TokenType.OPEN_PARENTHESE);
rules.Add(TokenType.END, TokenType.CLOSE_PARENTHESE);
return rules;
}
static bool isValid(Token prev, Token cur)
{
var rules = Parser.getRules();
return rules.ContainsKey(cur.type) && ((prev.type & rules[cur.type]) == prev.type);
}
public static ArrayList parse(string sourceText)
{
ArrayList result = new ArrayList();
int openParenthesesCount = 0;
Lexer lexer = new Lexer(sourceText);
Token prevToken = lexer.getStartToken();
Token currentToken = lexer.readNextToken();
string tmpText = "";
while (currentToken.type != TokenType.END)
{
if (currentToken.type == TokenType.OPEN_PARENTHESE)
{
openParenthesesCount++;
if (openParenthesesCount > 1)
{
tmpText += currentToken.token;
}
}
else if (currentToken.type == TokenType.CLOSE_PARENTHESE)
{
openParenthesesCount--;
if (openParenthesesCount < 0)
{
return Parser.Error();
}
if (openParenthesesCount > 0)
{
tmpText += currentToken.token;
}
}
else if (currentToken.type == TokenType.SIMPLE_TEXT)
{
tmpText += currentToken.token;
}
if (!Parser.isValid(prevToken, currentToken))
{
return Parser.Error();
}
if (openParenthesesCount == 1 && tmpText.Trim() != "")
{
result.Add(tmpText);
tmpText = "";
}
prevToken = currentToken;
currentToken = lexer.readNextToken();
}
if (openParenthesesCount != 0)
{
return Parser.Error();
}
if (!Parser.isValid(prevToken, currentToken))
{
return Parser.Error();
}
if (tmpText.Trim() != "")
{
result.Add(tmpText);
}
return result;
}
static ArrayList Error()
{
var er = new ArrayList();
er.Add("ERROR");
return er;
}
}
class Lexer
{
string _txt;
int _index;
public Lexer(string text)
{
this._index = 0;
this._txt = text;
}
public Token getStartToken()
{
return new Token(-1, TokenType.START, "");
}
public Token readNextToken()
{
if (this._index >= this._txt.Length)
{
return new Token(-1, TokenType.END, "");
}
Token t = null;
string txt = "";
if (this._txt[this._index] == '(')
{
txt = "(";
t = new Token(this._index, TokenType.OPEN_PARENTHESE, txt);
}
else if (this._txt[this._index] == ')')
{
txt = ")";
t = new Token(this._index, TokenType.CLOSE_PARENTHESE, txt);
}
else
{
txt = this._readText();
t = new Token(this._index, TokenType.SIMPLE_TEXT, txt);
}
this._index += txt.Length;
return t;
}
private string _readText()
{
string txt = "";
int i = this._index;
while (i < this._txt.Length && this._txt[i] != '(' && this._txt[i] != ')')
{
txt = txt + this._txt[i];
i++;
}
return txt;
}
}
class Token
{
public int position
{
get;
private set;
}
public TokenType type
{
get;
private set;
}
public string token
{
get;
private set;
}
public Token(int position, TokenType type, string token)
{
this.position = position;
this.type = type;
this.token = token;
}
}
[Flags]
enum TokenType
{
START = 1,
OPEN_PARENTHESE = 2,
SIMPLE_TEXT = 4,
CLOSE_PARENTHESE = 8,
END = 16
}
well, regex will do the job:
var text = #"(example (to (parsing nested paren) but) (first lvl only))";
var pattern = #"\(([\w\s]+) (\([\w\s]+ \([\w\s]+\) [\w\s]+\)) (\([\w\s]+\))\)*";
try
{
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
Match m = r.Match(text);
string group_1 = m.Groups[1].Value; //example
string group_2 = m.Groups[2].Value; //(to (parsing nested paren) but)
string group_3 = m.Groups[3].Value; //(first lvl only)
return new string[]{group_1,group_2,group_3};
}
catch(Exception ex){
return new string[]{"error"};
}
hopefully this helps, tested here in dotnetfiddle
Edit:
this might get you started into building the right expression according to whatever patterns you are falling into and maybe build a recursive function to parse the rest into the desired output :)
RegEx is not recursive. You either count bracket level, or recurse.
An non-recursive parser loop I tested for the example you show is..
string SplitFirstLevel(string s)
{
List<string> result = new List<string>();
int p = 0, level = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '(')
{
level++;
if (level == 1) p = i + 1;
if (level == 2)
{
result.Add('"' + s.Substring(p, i - p) + '"');
p = i;
}
}
if (s[i] == ')')
if (--level == 0)
result.Add('"' + s.Substring(p, i - p) + '"');
}
return "[" + String.Join(",", result) + "]";
}
Note: after some more testing, I see your specification is unclear. How to delimit orphaned level 1 terms, that is terms without bracketing ?
For example, my parser translates
(example (to (parsing nested paren) but) (first lvl only))
to:
["example ","(to (parsing nested paren) but) ","(first lvl only)"]
and
(example (to (parsing nested paren)) but (first lvl only))
to:
["example ","(to (parsing nested paren)) but ","(first lvl only)"]
In either case, "example" gets a separate term, while "but" is grouped with the first term. In the first example this is logical, it is in the bracketing, but it may be unwanted behaviour in the second case, where "but" should be separated, like "example", which also has no bracketing (?)

Set a string on a string referenced by string array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
string db;
ComboBox fieldBox = new ComboBox()
TextBox ValueBox = new TextBox()
ListBox dbValues = new ListBox()
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL
db = "John\t20\tMale\tNoob\n
Joe\t20\tMale\tMedium\n
Jessica\t27\tFemale\tExpert\n
John\t21\tMale\tMedium
";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
string[] db2 = db.Split('\n');
for (int i = 1; i < db2.Length - 1; i++)
{
//Display name and age in combobox
dbValues.Items.Add(db2[i].Split('\t')[0] + " - " + db2[i].Split('\t')[1]);
}
}
void ValueBoxKeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode != Keys.Enter)
return;
db.Split('\n')[dbValues.SelectedIndex].Split('\t')[fieldBox.SelectedIndex] = valueBox.Text;
MessageBox.Show("Value set: " +
db.Split('\n')[dbValues.SelectedIndex + 1].Split('\t')[fieldBox.SelectedIndex]
+ " to " + valueBox.Text + ".");
}
This is where it fails:
db.Split('\n')[dbValues.SelectedIndex].Split('\t')[fieldBox.SelectedIndex] = valueBox.Text;
I tried this, and tried to assign to db, but not working though. My original string is unchanged.
I do not want to convert to list and string back, i want to change directly.
How can i do this?
Your first problem is your string: unless you use # escaping you can't have your string cross multiple lines, and if you use # escaping you can't do \t or \n and retain their escaped meaning of tab and newline.
The second problem is a fundamental misunderstanding of the .NET string, string's are immutable. Split will create an array, there is no reference back to the original string, or the second array your splitting. You would need to do something like:
[TestClass]
public class StringTest
{
public TestContext TestContext { get; set; }
[TestMethod]
public void RewriteString()
{
var str = "Garry\t19\tMale\tNoob\n" +
"Joe\t25\tMale\tMedium\n" +
"Gary\t33\tFemale\tExpert";
var rows = str.Split('\n');
var columns = rows[0].Split('\t');
columns[0] = "Jerry";
rows[0] = string.Join("\t", columns);
str = string.Join("\n", rows);
TestContext.WriteLine(str);
}
}
Test Name: RewriteString
Test Outcome: Passed
Result StandardOutput: TestContext Messages:
Jerry 19 Male Noob
Joe 25 Male Medium
Gary 33 Female Expert
Would really hope there would be an easier way to do this, possibly with a Regex?
Now to really look at your (new) question. I have refactored exactly what you have, as I do not know your data situation I'm not entirely sure using a string as a database is a good idea: (this will compile without any references because of the use of dynamic).
public class SomeView
{
string db;
dynamic fieldBox = null;
dynamic valueBox = null;
dynamic dbValues = null;
dynamic MessageBox = null;
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL";
db = "John\t20\tMale\tNoob\n" +
"Joe\t20\tMale\tMedium\n" +
"Jessica\t27\tFemale\tExpert\n" +
"John\t21\tMale\tMedium";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
string[] db2 = db .Split('\n');
for (int i = 1; i < db2.Length - 1; i++)
{
var data = db2[i].Split('\t'); //expensive only do once
//Display name and age in combobox
dbValues.Items.Add(data[0] + " - " + data[1]);
}
}
protected string Transform(string value, int row, int column, string replacement, out string old)
{
var rows = value.Split('\n');
var columns = rows[row].Split('\t');
old = columns[column];
columns[column] = replacement;
rows[row] = string.Join("\t", columns);
return string.Join("\n", rows);
}
void ValueBoxKeyDown(object sender, dynamic e)
{
if (e.KeyCode != "enter")
return;
string old;
string newValue = this.Transform(db, dbValues.SelectedIndex, fieldBox.SelectedIndex, valueBox.Text, out old);
MessageBox.Show("Value set: " + old + " to " + valueBox.Text + ".");
}
}
So this is better:
public class SomeView
{
dynamic fieldBox = null;
dynamic valueBox = null;
dynamic dbValues = null;
dynamic MessageBox = null;
private List<Person> People = new List<Person>();
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL";
string db = "John\t20\tMale\tNoob\n" +
"Joe\t20\tMale\tMedium\n" +
"Jessica\t27\tFemale\tExpert\n" +
"John\t21\tMale\tMedium";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
People.Clear();
foreach(var row in db.Split('\n'))
{
var columns = row.Split('\t');
Person p = new Person();
p.Name = columns[0];
p.Age = int.Parse(columns[1]);
p.Sex = (Person.Sexs)Enum.Parse(typeof(Person.Sexs), columns[2]);
p.SkillLevel = (Person.SkillLevels)Enum.Parse(typeof(Person.SkillLevels), columns[2]);
People.Add(p);
dbValues.Items.Add(string.Format("{0}-{1}", p.Name, p.Age);
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public enum Sexs
{
Male,
Female
}
public Sexs Sex { get; set; }
public enum SkillLevels
{
Noob,
Medium,
Expert
}
public SkillLevels SkillLevel { get; set; }
}
void ValueBoxKeyDown(object sender, dynamic e)
{
if (e.KeyCode != "enter")
return;
Person p = this.People[dbValues.SelectedIndex];
switch((int)fieldBox.SelectedIndex)
{
case 0: p.Name = valueBox.Text; break;
case 1: p.Age = int.Parse(valueBox.Text); break;
case 2: p.Sex = (Person.Sexs)Enum.Parse(typeof(Person.Sexs), valueBox.Text); break;
case 3: p.SkillLevel = (Person.SkillLevels)Enum.Parse(typeof(Person.SkillLevels), valueBox.Text); break;
default: throw new NotImplementedException();
}
MessageBox.Show("Value set: " + old + " to " + valueBox.Text + ".");
}
}
However this is still garbage, since if you have a strongly typed data set you can actually bind this to form controls without directly manipulating the item.
https://msdn.microsoft.com/en-us/library/c8aebh9k(v=vs.110).aspx
You cannot change the return-value of a method returning a string as strings are immutable. What you can do instead is the following:
string myDatabase =
"Garry\t19\tMale\tNoob\n" +
"Joe\t25\tMale\tMedium\n" +
"Gary\t33\tFemale\tExpert";
var tmp = "";
foreach(var line in myString.Split('\n')) {
tmp = tmp + Regex.Replace(line, "^.*?(?=\\t)", myReplaceText);
}
myString = tmp;
This regex will search for everything before the very first tab within every line, replaces it by "Jerry"and and concatenates every so replaced line into myString.

Generate IL to decrease counter in for loop

I am hacking around with the Good For Nothing (GFN) compiler, trying to make it do a few different things. I am using the code from here: https://github.com/johandanforth/good-for-nothing-compiler
Regular GFN for loop:
var x = 0;
for x = 0 to 3 do
print x;
end;
This for loop always increments. I'd like to add decrement functionality:
var x = 0;
for x = 3 to 0 down //up for increment (works same as do)
print x;
end;
The main area I am struggling with is the CodeGen.
ForLoop class:
public class ForLoop : Stmt
{
public Stmt Body { get; set; }
public Expr From { get; set; }
public string Ident { get; set; }
public Expr To { get; set; }
public ArithOp Type { get; set; }
}
ArithOp enum:
public enum ArithOp
{
Add,
Sub,
Mul,
Div,
Up,
Down
}
Inside CodeGen.cs:
private void GenStmt(Stmt stmt)
{
//code omitted for brevity
else if (stmt is ForLoop)
{
// example:
// for x = 0 to 100 up
// "hello";
// end;
// x = 0
var forLoop = (ForLoop)stmt;
var assign = new Assign { Ident = forLoop.Ident, Expr = forLoop.From };
GenStmt(assign);
// jump to the test
var test = _il.DefineLabel();
_il.Emit(OpCodes.Br, test);
// statements in the body of the for loop
var body = _il.DefineLabel();
_il.MarkLabel(body);
GenStmt(forLoop.Body);
// to (increment/decrement the value of x)
_il.Emit(OpCodes.Ldloc, SymbolTable[forLoop.Ident]);
_il.Emit(OpCodes.Ldc_I4, 1);
_il.Emit(forLoop.Type == ArithOp.Up ? OpCodes.Add : OpCodes.Sub);
GenerateStoreFromStack(forLoop.Ident, typeof(int));
// **test** does x equal 100? (do the test)
_il.MarkLabel(test);
_il.Emit(OpCodes.Ldloc, SymbolTable[forLoop.Ident]);
GenerateLoadToStackForExpr(forLoop.To, typeof(int));
_il.Emit(OpCodes.Blt, body);
}
}
private void GenerateStoreFromStack(string name, Type type)
{
if (!SymbolTable.ContainsKey(name))
throw new Exception("undeclared variable '" + name + "'");
var locb = SymbolTable[name];
var localType = locb.LocalType;
if (localType != type)
throw new Exception(string.Format("'{0}' is of type {1} but attempted to store value of type {2}", name,
localType == null ? "<unknown>" : localType.Name, type.Name));
_il.Emit(OpCodes.Stloc, SymbolTable[name]);
}
private void GenerateLoadToStackForExpr(Expr expr, Type expectedType)
{
Type deliveredType;
if (expr is StringLiteral)
{
deliveredType = typeof(string);
_il.Emit(OpCodes.Ldstr, ((StringLiteral)expr).Value);
}
else if (expr is IntLiteral)
{
deliveredType = typeof(int);
_il.Emit(OpCodes.Ldc_I4, ((IntLiteral)expr).Value);
}
else if (expr is Variable)
{
var ident = ((Variable)expr).Ident;
deliveredType = expr.GetType();
if (!SymbolTable.ContainsKey(ident))
{
throw new Exception("undeclared variable '" + ident + "'");
}
_il.Emit(OpCodes.Ldloc, SymbolTable[ident]);
}
else if (expr is ArithExpr)
{
var arithExpr = (ArithExpr)expr;
var left = arithExpr.Left;
var right = arithExpr.Right;
deliveredType = expr.GetType();
GenerateLoadToStackForExpr(left, expectedType);
GenerateLoadToStackForExpr(right, expectedType);
switch (arithExpr.Op)
{
case ArithOp.Add:
_il.Emit(OpCodes.Add);
break;
case ArithOp.Sub:
_il.Emit(OpCodes.Sub);
break;
case ArithOp.Mul:
_il.Emit(OpCodes.Mul);
break;
case ArithOp.Div:
_il.Emit(OpCodes.Div);
break;
default:
throw new NotImplementedException("Don't know how to generate il load code for " + arithExpr.Op +
" yet!");
}
}
else
{
throw new Exception("don't know how to generate " + expr.GetType().Name);
}
if (deliveredType == expectedType) return;
if (deliveredType != typeof (int) || expectedType != typeof (string))
throw new Exception("can't coerce a " + deliveredType.Name + " to a " + expectedType.Name);
_il.Emit(OpCodes.Box, typeof (int));
_il.Emit(OpCodes.Callvirt, typeof (object).GetMethod("ToString"));
}
This currently generates an .exe that does nothing. Sources I have looked at to help solve this: http://www.codeproject.com/Articles/3778/Introduction-to-IL-Assembly-Language#Loop and https://ninjaferret.wordpress.com/2009/12/23/msil-4-for-loops/. I just don't know enough IL
Do this in C# code to get insight:
for (int ix = 0; ix < 3; ++ix) // up
for (int ix = 3; ix > 0; --ix) // down
There are two changes, you got the difference in the inc/dec operator. You didn't get the change in the loop termination condition. Which makes this the bug:
_il.Emit(OpCodes.Blt, body);
You'll have to invert that to Opcodes.Bgt

A c style directive in c# that allows for using one expression twice #define x(k) {#k, k}

In C it is possible to write a macro function that replaces an input with the input as a string.
#define x(k) {#k, k}
'(4)' would generate '{"4", 4}'
I have a usecase in C# where i want to pass an input like this to a unit test.
private void AssertInt64Expression(Int64 i, string str)
{
Assert.AreEqual(i, MathFactory.make(str));
}
[Test]
public void ParseBasic()
{
AssertInt64Expression(4, "4");
AssertInt64Expression(2+3, "2+3");
AssertInt64Expression(7-11, "7-11");
AssertInt64Expression(7-11 *2, "7-11 *2");
AssertInt64Expression(7 - 11 * 2, "7 - 11 * 2");
}
I am essentially repeating the information (including whitespace) here, how can i use something like the c style macro to solve this in c#?
edit:
essentially i would love to write:
private void AssertInt64Expression(GeneratorMagic magic)
{
Assert.AreEqual(magic.ToCode(), MathFactory.make(magic.ToString()));
}
[Test]
public void ParseBasic()
{
AssertInt64Expression(<#7 - 11 * 2#>);
}
I am aware that this would not compile.
edit:
I added a code snippet as an answer to illustrate what i am looking for.
However this snippet runs very slow, since i need it to refactor my unit tests into cleaner code with less repetition i need the snippet to run faster.
The snippet essentially provides the magic from the previous edit as a KeyValuePair.
You can use a custom number class with overloaded operators.
static void Main(string[] args)
{
Console.WriteLine((Number)1 + 5);
Console.WriteLine((int)((Number)1 + 5 + 6));
}
public class Number
{
private string _representation = "";
private int _number = 0;
private Number(int n)
{
_number = n;
_representation = n.ToString();
}
public Number Plus(int n)
{
_representation += " + " + n;
_number += n;
return this;
}
public static Number operator +(Number value1, int value2)
{
return value1.Plus(value2);
}
public static explicit operator Number(int val)
{
return new Number(val);
}
public static explicit operator int(Number num)
{
return num._number;
}
public override string ToString()
{
return _representation;
}
}
The following snippet does what i need but it seems to run horribly slow.
private KeyValuePair<String, Int64> GenerateCodeInt64(String mathKey)
{
string codeNamespace = "MathTestCalculator";
string codeClassName = "MathTestCalculator";
string codeMethodName = "Value";
Int64 I64Value = 0;
StringBuilder codeBuilder = new StringBuilder();
codeBuilder
.Append("using System;\n")
.Append("namespace ").Append(codeNamespace).Append(" {\n")
.Append("class ").Append(codeClassName).Append("{\n")
.Append("public Int64 ").Append(codeMethodName).Append("(){\n")
.Append("return (Int64)(").Append(mathKey).Append(");}}}\n");
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
CompilerResults results = CodeDomProvider
.CreateProvider("CSharp")
.CompileAssemblyFromSource(cp, codeBuilder.ToString());
if (results.Errors.Count > 0)
{
StringBuilder error = new StringBuilder();
error.Append("Unable to evaluate: '").Append(mathKey).Append("'\n");
foreach (CompilerError CompErr in results.Errors)
{
error
.Append("Line number ").Append(CompErr.Line)
.Append(", Error Number: ").Append(CompErr.ErrorNumber)
.Append(", '").Append(CompErr.ErrorText).Append(";\n");
}
throw new Exception(error.ToString());
}
else
{
Type calcType = results.CompiledAssembly.GetType(codeNamespace + "." + codeClassName);
object o = Activator.CreateInstance(calcType);
I64Value = (Int64)calcType.GetMethod(codeMethodName).Invoke(o, null);
}
return new KeyValuePair<string, long>(mathKey, I64Value);
}

Categories