VisualBasicValue: доступ к пользовательским классам и его методам свойствам

#c# #workflow-foundation-4

#c# #рабочий процесс-foundation-4

Вопрос:

Предположим, у меня есть пользовательский класс (любой класс) со своими методами и свойствами:

 public class Test
{
    public string MyString { get; set; }
    public bool MyBool { get; set; }

    public override string ToString()
    {
        return "Test Class : "   this.MyString   " - "   MyBool;
    }
}
  

Теперь я хочу перемещать и обрабатывать его свойства между действиями WF4 с помощью VisualBasicValue<T> . Например:

 public class Program
{
    static void Main(string[] args)
    {

        Test testClass = new Test() 
        {
            MyString = "some string",
            MyBool = true
        };

        Sequence wf = new Sequence()
        {
            Variables =
            {
                new Variable<Test>("varName", testClass),
            },

            Activities =
            {
                new WriteLine() { Text = new VisualBasicValue<string>(""Test Class Properties: " amp; varName.MyString amp; "-" amp; varName.MyBool") },
                new WriteLine() { Text = new VisualBasicValue<string>(""Test Class ToString(): " amp; varName") }
            }
        };

        WorkflowInvoker.Invoke(wf);

        Console.ReadKey();
    }
}
  

Этот код компилируется без проблем. Переменная может обрабатывать любой класс, но во время выполнения она, похоже, жалуется на использование пользовательского класса. Некоторое исключение, подобное:

 The following errors were encountered while processing the workflow tree:
'Literal<Test>': Literal only supports value types and the immutable type System.String.  The type WorkflowConsoleApplication3.Test cannot be used as a literal.
'VisualBasicValue<String>': Compiler error(s) encountered processing expression ""Test Class ToString(): " amp; varName".
  

Оператор ‘amp;’ не определен для типов ‘String’ и ‘workflowconsoleapplication 3.Тест’.

Я читал, что вы можете сделать что-то в этом роде:

 VisualBasicSettings vbSettings = new VisualBasicSettings();
vbSettings.ImportReferences.Add(new VisualBasicImportReference()
{
    Assembly = typeof(Test).Assembly.GetName().Name,
    Import = typeof(Test).Namespace
});

// construct workflow

VisualBasic.SetSettings(wf, vbSettings);

WorkflowInvoker.Invoke(wf);
  

Но, похоже, это не помогает. Любая помощь?

PS: В той же теме, может кто-нибудь привести мне небольшой пример, как где использовать VisualBasicReference<T>' with OutArgument`? Кажется, это то, что я могу использовать на более позднем этапе, но я должен найти какой-либо пример.

Ответ №1:

Я внес пару изменений, чтобы заставить ваш код работать.

  1. Конструктор переменных изменен, чтобы использовать перегрузку ActivityFunc
  2. Вторая строка записи должна явно вызывать toString() в выражении

Исправленный код выглядит следующим образом

 private static void Main(string[] args)
{
    var testClass = new Test { MyString = "some string", MyBool = true };
    var wf = new Sequence
    {
        Variables = {
                        // Changed to use ActivityFunc so testClass is not interpreted as a literal
                        new Variable<Test>("varName", ctx => testClass), 
                    }, 
        Activities =
            {
                new WriteLine
                    {
                        Text =
                            new VisualBasicValue<string>(
                            ""Test Class Properties: " amp; varName.MyString amp; "-" amp; varName.MyBool")
                    }, 
                    // Changed to call ToString explicitly
                    new WriteLine { Text = new VisualBasicValue<string>(""Test Class ToString(): " amp; varName.ToString()") }
            }
    };
    var settings = new VisualBasicSettings();
    settings.ImportReferences.Add(
        new VisualBasicImportReference
            {
                Assembly = typeof(Test).Assembly.GetName().Name, Import = typeof(Test).Namespace 
            });

    // construct workflow
    VisualBasic.SetSettings(wf, settings);
    WorkflowInvoker.Invoke(wf);
    Console.ReadKey();
}
  

Еще одна вещь. Некоторые задавались вопросом, зачем было вызывать Test.toString() явно с помощью оператора Concat VB. Это любопытная проблема, и это одно из мест, где тип, объявленный в C #, отличается от типа, объявленного в VB.

C # использует оператор как для сложения, так и для конкатенации, где VB имеет оператор amp; для concat и конкретную инструкцию IL op_Concat.

Если вы объявляете свой тип в VB, вы можете перегрузить оператор amp;, чтобы исключить необходимость вызова toString() в вашем выражении.

Например

 Public Class Test
    Public Property MyString As String
    Public Property MyBool As Boolean

    Public Overrides Function ToString() As String
        Return "Test Class : " amp; MyString   " - " amp; MyBool
    End Function

    Public Shared Operator amp;(ByVal left As String, ByVal right As Test) As String
        Return left amp; "-" amp; right.ToString
    End Operator
End Class
  

При работе над проблемами, подобными VB, я часто просто создаю консольные приложения VB, чтобы протестировать что-то помимо рабочего процесса

 Module Module1

    Dim varName As New Test With {.MyBool = True, .MyString = "some string"}

    Sub Main()
        Console.WriteLine("Test Class Properties: " amp; varName.MyString amp; "-" amp; varName.MyBool)
        Console.WriteLine("Test Class ToString(): " amp; varName)
        Console.ReadKey()
    End Sub

End Module
  

Идентификатор, выданный для этого приложения, показывает оператора

 IL_002f:  ldstr      "Test Class ToString(): "
IL_0034:  ldsfld     class VBTest.Test VBTest.Module1::varName
IL_0039:  call       string VBTest.Test::op_Concatenate(string, class VBTest.Test)
IL_003e:  call       void [mscorlib]System.Console::WriteLine(string)
  

Комментарии:

1. Да! В этом-то и проблема. Спасибо.

Ответ №2:

Работает следующий код. Обратите внимание на то, как я инициализирую переменную с помощью лямбды вместо фиксированного значения, а второе выражение VB использует вместо amp;. Последнее для меня выглядит как ошибка, и я собираюсь проследить за этим.

 static void Main()
{
    Test testClass = new Test()
    {
        MyString = "some string",
        MyBool = true
    };

    Sequence wf = new Sequence()
    {
        Variables =
        {
            new Variable<Test>("varName", c => testClass),
        },

        Activities =
        {
            new WriteLine() { Text = new VisualBasicValue<string>(""Test Class Properties: " amp; varName.MyString amp; "-" amp; varName.MyBool") },
            new WriteLine() { Text = new VisualBasicValue<string>(""Test Class ToString(): "   varName") }
        }
    };

    var vbSettings = new VisualBasicSettings();
    vbSettings.ImportReferences.Add(new VisualBasicImportReference()
    {
        Assembly = typeof(Test).Assembly.GetName().Name,
        Import = typeof(Test).Namespace
    });


    VisualBasic.SetSettings(wf, vbSettings);
    WorkflowInvoker.Invoke(wf);

    Console.ReadKey();
}
  

Мне пришлось внести небольшое изменение в тестовый класс, чтобы добавить оператор для конкатенации строк.
тест открытого класса
{
общедоступная строка myString { получить; установить; }
общедоступный bool MyBool { получить; установить; }

     public override string ToString()
    {
        return "Test Class : "   this.MyString   " - "   MyBool;
    }

    public static string operator  (string s, Test t)
    {
        return s   t.ToString();
    }
}
  

Комментарии:

1. Я уже исправил эту ошибку вскоре после публикации вопроса, но проблема остается. Это странно, но, похоже, это правильное использование. Знаете ли вы что-нибудь о VisualBasicSettings и VisualBasicImportReference . Держу пари, что в этом проблема.

2. Они говорят об этом здесь

3. Какие сообщения об ошибках вы получаете и какое текущее выражение VB вы используете?

4. Сообщения об ошибках приведены в сообщении вопроса выше. В основном это жалобы на то, что тестовый класс не может использоваться как литерал . Я использую точно такие же выражения, как у вас, я обновил ими исходный пост.