views:

228

answers:

4

I've researched on this but couldn't find anything solid and wanted to see if someone can point me in the right direction. I'm trying to see if Codedom can handle strings and concantination between different languages, without me setting up conditional strings per language.

For example, I need to generate the following exactly as shown below in both C# and VB.NET via Codedom:

C#

errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");  

VB.NET

errorMsg = errorMsg.Replace(""""c, "'"c).Replace(ChrW(13) & ChrW(10), "\n")
System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(""Unhandled Error in Silverlight Application " + errorMsg + """);")

The CodeMethodInvokeExpression for errorMsg.Replace and System.Windows.Browser.HtmlPage.Window.Eval is simple enough, it's the string inside them that I can't figure out if Codedom can automatically handle.

+1  A: 

Update: I just tried the following code:

VBCodeProvider vbProvider = new VBCodeProvider();
CSharpCodeProvider csProvider = new CSharpCodeProvider();

var errorMessagePart1 = new CodePrimitiveExpression("Unhandled Error in Silverlight Application \"");
var errorMessagePart2 = new CodeVariableReferenceExpression("errorMsg");
var errorMessagePart3 = new CodePrimitiveExpression("\"");
var errorMessage = new CodeBinaryOperatorExpression(new CodeBinaryOperatorExpression(errorMessagePart1, CodeBinaryOperatorType.Add, errorMessagePart2), CodeBinaryOperatorType.Add, errorMessagePart3);
var expression = new CodeThrowExceptionStatement(new CodeObjectCreateExpression("Error", errorMessage));

StringWriter writer = new StringWriter();
vbProvider.GenerateCodeFromStatement(expression, writer, new CodeGeneratorOptions());
string vb = writer.ToString();
writer = new StringWriter();
csProvider.GenerateCodeFromStatement(expression, writer, new CodeGeneratorOptions());
string cs = writer.ToString();

Console.WriteLine(vb);
Console.WriteLine(cs);

It prints out:

Throw New [Error]((("Unhandled Error in Silverlight Application """ + errorMsg) _ 
    + """"))

throw new Error((("Unhandled Error in Silverlight Application \"" + errorMsg)
    + "\""));

Which looks to me like a VB version and a C# version. Not a whole lot you can do about the spurious parentheses, but shouldn't cause any harm.

Kirk Woll
No, unfortunately it doesn't work in VB<->C# in either case.
Otaku
Updated my answer, please see if this works for you.
Kirk Woll
+1. A valiant effort, really interesting how you did that. Unfortunately I need the whole thing as a string and haven't been able to work that out from the ode above.
Otaku
+4  A: 

Unfortunately code primitives, when combined, don’t always produce desired results because the provider will take certain liberties to interpret intent. The way around this is to use a CodeSnippetExpression.

Here’s code (VB.NET & C#) that works to produce the Eval statements that you listed in your question. Feel free to use whichever works best for you:

VB.NET Version

Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Text
Imports System.IO
Imports Microsoft.CSharp

Public Class PrintEvalStatement
    Public provider As CodeDomProvider

    Sub New()
        Dim left As New CodePrimitiveExpression("throw new Error(""Unhandled Error in Silverlight Application ")
        Dim middle As New CodeVariableReferenceExpression("errorMsg")
        Dim right As New CodePrimitiveExpression(""");")

        Dim targetObject = New CodeTypeReferenceExpression("System.Windows.Browser.HtmlPage.Window")
        Dim methodName = "Eval"

        provider = New VBCodeProvider()
        Dim vbStatement As String = ConcatStatement(left, middle, right, targetObject, methodName)

        provider = New CSharpCodeProvider()
        Dim csStatement As String = ConcatStatement(left, middle, right, targetObject, methodName)

        Console.WriteLine(vbStatement)
        Console.WriteLine(csStatement)
        Console.ReadLine()
    End Sub

    Private Function ConcatStatement(ByVal left As CodePrimitiveExpression,
                                     ByVal middle As CodeVariableReferenceExpression,
                                     ByVal right As CodePrimitiveExpression,
                                     ByVal targetObject As CodeTypeReferenceExpression,
                                     ByVal methodName As String) As String
        Dim evalMessage As New CodeExpression
        evalMessage = ConcatString(left, middle, right)

        Dim eval As New CodeMethodInvokeExpression(targetObject, methodName, evalMessage)
        Dim evalStatement As New CodeExpressionStatement(eval)
        Dim sw As StringWriter = New StringWriter()

        Using tx As TextWriter = New StringWriter()
            provider.GenerateCodeFromStatement(evalStatement, tx, New CodeGeneratorOptions())
            Return tx.ToString()
        End Using
    End Function
    Private Function ConcatString(ByVal left As CodeExpression,
                                  ByVal middle As CodeExpression,
                                  ByVal right As CodeExpression) As CodeExpression
        Return New CodeSnippetExpression(CodeToString(left) + " + " + CodeToString(middle) + " + " + CodeToString(right))
    End Function
    Private Function CodeToString(ByVal expr As CodeExpression) As String
        Using tx As TextWriter = New StringWriter()
            provider.GenerateCodeFromExpression(expr, tx, New CodeGeneratorOptions())
            Return tx.ToString()
        End Using
    End Function


End Class

C# Version

using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

namespace CodeDom
{
    class Program
    {       
        static CodeDomProvider provider;

        static void Main(string[] args)
        {
            Program shell = new Program();
            provider = new VBCodeProvider();
            CodePrimitiveExpression left = new CodePrimitiveExpression("throw new Error(\"Unhandled Error in Silverlight Application\")");
            CodeVariableReferenceExpression middle = new CodeVariableReferenceExpression("errorMsg");
            CodePrimitiveExpression right = new CodePrimitiveExpression("\");");

            CodeTypeReferenceExpression targetObject = new CodeTypeReferenceExpression("System.Windows.Browser.HtmlPage.Window");
            string methodName = "Eval";

            string vbStatement =  shell.ConcatStatement(left, middle, right, targetObject, methodName);

            provider = new CSharpCodeProvider();

            string csStatement = shell.ConcatStatement(left, middle, right, targetObject, methodName);

            Console.WriteLine(vbStatement);
            Console.WriteLine(csStatement);
            Console.ReadLine();

        }

        public string ConcatStatement(CodePrimitiveExpression left, CodeVariableReferenceExpression middle, CodePrimitiveExpression right, CodeTypeReferenceExpression targetObject, string methodName)
        {
            CodeExpression evalMessage = new CodeExpression();
            evalMessage = ConcatString(left, middle, right);

            CodeMethodInvokeExpression eval = new CodeMethodInvokeExpression(targetObject, methodName, evalMessage);
            CodeExpressionStatement evalStatement = new CodeExpressionStatement(eval);
            using (TextWriter tx = new StringWriter())
            {
                provider.GenerateCodeFromStatement(evalStatement, tx, new CodeGeneratorOptions());
                return tx.ToString();
            }
        }

        private CodeExpression ConcatString(CodeExpression left, CodeExpression middle, CodeExpression right) {
            return new CodeSnippetExpression(CodeToString(left) + " + " + CodeToString(middle) + " + " + CodeToString(right));
        }

        private string CodeToString(CodeExpression expr) {
            using (TextWriter tx = new StringWriter()) {
                provider.GenerateCodeFromExpression(expr,tx, new CodeGeneratorOptions());
                return tx.ToString();
            }
        }
    }
}
Alison
+1. Very comprehensive. Let me test this out.
Otaku
Worked great, thank you!
Otaku
+1  A: 

You could call string.Concat instead of using the + operator unless you need to generate the code exactly as shown.

CodePrimitiveExpression throwstring = new CodePrimitiveExpression("throw new Error(\"Unhandled Error in Silverlight Application ");
CodeVariableReferenceExpression errorMsg = new CodeVariableReferenceExpression("errorMsg");
CodePrimitiveExpression end = new CodePrimitiveExpression("\");");

CodeTypeReferenceExpression targetObject = new CodeTypeReferenceExpression("System.Windows.Browser.HtmlPage.Window");
CodeTypeReferenceExpression str = new CodeTypeReferenceExpression(typeof(string));
CodeMethodInvokeExpression concat = new CodeMethodInvokeExpression(str,"Concat",throwstring,errorMsg,end);
CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(targetObject, "Eval"), concat);

Outputs C#:

System.Windows.Browser.HtmlPage.Window.Eval(string.Concat("throw new Error(\"Unhandled Error in Silverlight Application ", errorMsg, "\");"))

VB:

System.Windows.Browser.HtmlPage.Window.Eval(String.Concat("throw new Error(""Unhandled Error in Silverlight Application ", errorMsg, """);"))
Kris
Sorry, this doesn't really help much. As stated in the question above, I need to generate those strings/statements. I'll edit the question to add the words "exactly as shown below".
Otaku
A: 

The class CodeTypeReference should help you (http://msdn.microsoft.com/en-us/library/system.codedom.codetypereference.aspx), just as Alison used.

SimpleCoder
Sorry, this isn't particularly helpful.
Otaku