Codedom и обработка строк

Я исследовал это, но не смог найти ничего надежного и хотел посмотреть, может ли кто-нибудь указать мне правильное направление. Я пытаюсь выяснить, может ли Codedom обрабатывать строки и конкантинацию между разными языками, не устанавливая условные строки для каждого языка.

Например, мне нужно сгенерировать следующее точно так, как показано ниже как на C#, так и на VB.NET через Codedom:

С#

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 + """);")

CodeMethodInvokeExpression для errorMsg.Replace и System.Windows.Browser.HtmlPage.Window.Eval достаточно прост, это строка внутри них, которую я не могу понять, может ли Codedom автоматически обрабатывать.


person Todd Main    schedule 14.08.2010    source источник
comment
Я не понимаю ваш пример С#. Ваш строковый литерал содержит две двойные кавычки подряд. Это не законно С#. Как ни странно, ваш пример VB.NET для литерала является действительным C#, так почему бы просто не использовать его?   -  person Kirk Woll    schedule 14.08.2010
comment
@Kirk Woll: пример не мой, это Microsoft. Это то, что создается в App.xaml.vb или App.xaml.cs для нового проекта Silverlight в VS. То, что он делает, это выводит сообщение об ошибке на Javascript.   -  person Todd Main    schedule 14.08.2010
comment
Но я не понимаю, как пример MS мог бы скомпилироваться. Вы предполагаете, что это так?   -  person Kirk Woll    schedule 14.08.2010
comment
Я с Кирком Уоллом в этом вопросе, я не понимаю, как этот C # может компилироваться   -  person PsychoCoder    schedule 15.08.2010
comment
Он компилируется все время. Попробуйте сами. Создайте новый проект Silverlight в VS2008 или VS2010. Обратите внимание, что приведенный выше код находится в подпрограмме ReportErrorToDOM в App.xaml.cs. Скомпилировать.   -  person Todd Main    schedule 15.08.2010
comment
Я просто сделал именно то, что вы предложили. Вот что я вижу в своем App.xaml.cs: System.Windows.Browser.HtmlPage.Window.Eval(throw new Error(\Unhandled Error in Silverlight Application + errorMsg + \);); Это не соответствует приведенному выше примеру: System.Windows.Browser.HtmlPage.Window.Eval(throw new Error(Unhandled Error in Silverlight Application + errorMsg +);)   -  person Kirk Woll    schedule 15.08.2010
comment
Тьфу, мои искренние извинения, у меня были VB и C # задом наперед.   -  person Todd Main    schedule 15.08.2010
comment
@Kirk woll просто для того, чтобы запутать вещи в C #, на самом деле может быть допустимым в строковом литерале, но только, если формат литерала @....   -  person Rune FS    schedule 20.08.2010
comment
@Rune, нет, это совсем не так. Иначе как бы вы закрыли строковый литерал? Вы хоть пробовали? ;)   -  person Kirk Woll    schedule 20.08.2010
comment
@ Кирк, да, я пробовал, и да, это работает :). Если бы это было не так, как бы вы экранировали a в строке? вы не можете использовать \ для экранирования, это литерал, поэтому \ будет просто интерпретироваться как обратная косая черта, а затем будет окончание qoute. и для закрытия литерала я бы просто использовал один . Попробуйте, и вы увидите, что это работает, если вы начинаете литерал с @, а не   -  person Rune FS    schedule 20.08.2010
comment
@Rune, я попробовал это перед публикацией. Вы здесь совершенно неправы. А именно: msdn.microsoft.com/en-us/ library/aa691090(VS.71).aspx: однобуквенный-строковый-литеральный-символ: Любой символ, кроме   -  person Kirk Woll    schedule 20.08.2010
comment
@Kirk: интересную ссылку вы там разместили. Честно говоря, мог бы найти лучший мой eslf :) В дословном строковом литерале символы между разделителями интерпретируются дословно, единственным исключением является кавычка-escape-последовательность и 'quote-escape-sequence:' с кодом примера также из MSDN: string f = @Joe поздоровался со мной; // Джо поздоровался со мной.   -  person Rune FS    schedule 20.08.2010
comment
@Rune, ты абсолютно прав. Я тоже пробовал, но, должно быть, что-то не так с моим примером, когда я это делал. Спасибо за упорство в своем несогласии со мной. Позвольте мне узнать что-то новое. ;)   -  person Kirk Woll    schedule 20.08.2010


Ответы (4)


К сожалению, примитивы кода в сочетании не всегда дают желаемые результаты, потому что провайдер допускает определенные вольности в интерпретации намерений. Обойти это можно с помощью CodeSnippetExpression.

Вот код (VB.NET и C#), который работает для создания операторов Eval, которые вы указали в своем вопросе. Не стесняйтесь использовать то, что лучше всего подходит для вас:

Версия VB.NET

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#

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();
            }
        }
    }
}
person NakedBrunch    schedule 17.08.2010

Обновление: я только что попробовал следующий код:

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);

Он распечатывает:

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

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

Что выглядит для меня как версия VB и версия C #. Не так много вы можете сделать с ложными скобками, но это не должно причинить никакого вреда.

person Kirk Woll    schedule 15.08.2010
comment
+1. Доблестная попытка, очень интересно, как вы это сделали. К сожалению, мне нужно все это как строку, и я не смог понять это из оды выше. - person Todd Main; 17.08.2010

Вы можете вызвать string.Concat вместо использования оператора +, если вам не нужно генерировать код точно так, как показано.

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);

Выводит С#:

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, """);"))
person Kris    schedule 17.08.2010
comment
Извините, это мало помогает. Как указано в вопросе выше, мне нужно сгенерировать эти строки/операторы. Я отредактирую вопрос, чтобы добавить слова точно так, как показано ниже. - person Todd Main; 18.08.2010

Вам должен помочь класс CodeTypeReference (http://msdn.microsoft.com/en-us/library/system.codedom.codetypereference.aspx), как и Элисон.

person Chris Laplante    schedule 18.08.2010
comment
Извините, это не особенно полезно. - person Todd Main; 18.08.2010