VisualBasicValue<T>: Access custom classes and its methods\properties

我的梦境 提交于 2019-12-12 06:32:59

问题


Suppose I've a custom class (any class), with its methods and properties:

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

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

Now I want to move and handle its properties between WF4 activities using VisualBasicValue<T>. For example:

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: \" & varName.MyString & \"-\" & varName.MyBool") },
                new WriteLine() { Text = new VisualBasicValue<string>("\"Test Class ToString(): \" & varName") }
            }
        };

        WorkflowInvoker.Invoke(wf);

        Console.ReadKey();
    }
}

This code compiles without a problem. Variable can handle any kind of class, but while running it seems to complain of the custom class usage. Some exception like:

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(): " & varName".

Operator '&' is not defined for types 'String' and 'WorkflowConsoleApplication3.Test'.

I've read that you can do something along this lines:

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

But that doesn't seems to do the trick. Any help?

PS: At the same topic, can someone give me a little example how\where to use VisualBasicReference<T>' withOutArgument`? It seems something I can use at a later stage but I'm to find any kind of example.


回答1:


I made a couple of changes to make your code work.

  1. The Variable constructor is changed to use the ActivityFunc overload
  2. The second WriteLine needs to call ToString() explicitly in the expression

The corrected code is as follows

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: \" & varName.MyString & \"-\" & varName.MyBool")
                    }, 
                    // Changed to call ToString explicitly
                    new WriteLine { Text = new VisualBasicValue<string>("\"Test Class ToString(): \" & 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();
}

One more thing. Some have questioned why it was necessary to call Test.ToString() explicitly with the VB Concat operator. This is a curious issue and it is one of the places where a type declared in C# differs from a type declared in VB.

C# uses the + operator for both addition and concatenation where VB has the & operator for concat and a specific IL instruction op_Concat.

If you declare your type in VB, you can overload the & operator to eliminate the need to call ToString() in your expression.

For example

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

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

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

When working on problems like in VB I often just create VB console apps to test things out apart from Workflow

Module Module1

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

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

End Module

The IL emitted for this app shows the operator

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)



回答2:


The following code works. Note the way I initialize the variable with a lambda instead of a fixed value and the second VB expression uses a + instead of an &. The last looks like a bug to me and I am going to follow up on that.

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: \" & varName.MyString & \"-\" & 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();
}

I had to make a small change to the Test class to add a + operator for the string concatenation. public class Test { public string MyString { get; set; } public bool MyBool { get; set; }

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

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


来源:https://stackoverflow.com/questions/5802497/visualbasicvaluet-access-custom-classes-and-its-methods-properties

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!