2

I am using GenerateCodeFromCompileUnit and IndentedTextWriter to Generate Code from C# Source File. Doing this I am able to Generate a .cs file. But I am seeing a special character @ is inserted before every declared variable and Function Return types. Here's is my code.

I am using a Class to Hold Function details to be Inserted.

Dim provider As Microsoft.CSharp.CSharpCodeProvider
Dim options = New System.CodeDom.Compiler.CompilerParameters
options.ReferencedAssemblies.Add("System.dll")
options.GenerateExecutable = False
options.GenerateInMemory = True
options.IncludeDebugInformation = True
options.OutputAssembly = "FunctionEvaluated.dll"

Dim compileUnit As System.CodeDom.CodeCompileUnit
compileUnit = New CodeDom.CodeCompileUnit
Dim codeNamespace = New CodeDom.CodeNamespace("NewNamespace")

compileUnit.Namespaces.Add(codeNamespace)

Dim classForCompile = New CodeDom.CodeTypeDeclaration("NewAction")
codeNamespace.Types.Add(classForCompile)

Dim functionToEvaluate = New CodeDom.CodeMemberMethod()

Dim returnType As CodeDom.CodeTypeReference

If functionClass.FunctionNameAndType.Select(Function(fn) fn.Value)(0).ToString() = "void" Then
    returnType = New CodeDom.CodeTypeReference("void")
Else

    returnType = New CodeDom.CodeTypeReference(functionClass.FunctionNameAndType.Select(Function(fn) fn.Value)(0).ToString())
End If

Dim parameterExpressionCollection = New CodeDom.CodeParameterDeclarationExpressionCollection()

For Each ip In functionClass.FunctionNameIP


    For Each fnIP In ip.Value
        Dim parameterExpression As CodeDom.CodeParameterDeclarationExpression
        parameterExpression = New CodeDom.CodeParameterDeclarationExpression(fnIP.Value.ToString(), fnIP.Key.ToString())

        parameterExpressionCollection.Add(parameterExpression)
    Next
Next

functionToEvaluate.Name = functionClass.FunctionNameAndType.Select(Function(fn) fn.Key)(0).ToString()
functionToEvaluate.ReturnType = returnType
functionToEvaluate.Parameters.AddRange(parameterExpressionCollection)


classForCompile.Members.Add(functionToEvaluate)

provider = New Microsoft.CSharp.CSharpCodeProvider
Dim sourceFile As String
sourceFile = "FunctionEvaluated.cs"
Dim tw As IndentedTextWriter = New IndentedTextWriter(New StreamWriter(sourceFile, False), vbTab)
provider.GenerateCodeFromCompileUnit(compileUnit, tw, New CodeGeneratorOptions())
tw.Close()

Output

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NewNamespace {
    
    
    public class NewAction {
        
        private @int functionAdd(@int b, @int a) {
        }
    }
}
coding_cs
  • 77
  • 9
  • BTW does your code really work with `New` in upper case, instead of `new`? – Christopher Hamkins Dec 15 '21 at 13:59
  • By the way the above code to I used to generate is written in VB.Net so New is in upper case. – coding_cs Dec 15 '21 at 14:49
  • Oops sorry I didn't even notice that. Have to check if Type.GetType(String) is available then. Based on https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/gettype-operator I suppose it is. You may need to use "Integer" as the string instead of "int" though. – Christopher Hamkins Dec 15 '21 at 14:53
  • But functionClass.FunctionNameAndType.Select(Function(fn) fn.Value)(0).ToString()) is having "int". If I pass it to Type.GetType("int") it is returning "Nothing". – coding_cs Dec 15 '21 at 14:57
  • "Integer" is the same type in Visual Basic as "int" in c# so the function would expect "Integer" when called from Visual Basic, and would output "int" in the code. Or you could get rid of the call to Type.GetType() but use "Int32" in your data instead of "int". "Int32" is not a keyword so it would not be output with the preceding @. – Christopher Hamkins Dec 15 '21 at 15:02
  • how to parse other values, I am passing "int", "string","void" and "object" as String. Can I parse these as well? – coding_cs Dec 15 '21 at 15:06
  • I would expect that you need to use the Basic equivalents, i.e. "Integer", "String", "Void" , "Object" as the parameters to Type.GetType, but the output code would have int, string, void and object in it. – Christopher Hamkins Dec 15 '21 at 15:14
  • Check out https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_system/html/tcsysmgr_datatypecomparison.htm&id= to find the equivalents. Working in c#, I find that using CodeTypeReference() without arguments is interpreted as "void". – Christopher Hamkins Dec 15 '21 at 15:23

1 Answers1

3

I believe your problem is in the lines

New CodeDom.CodeTypeReference(functionClass.FunctionNameAndType.Select(Function(fn) fn.Value)(0).ToString())

and

parameterExpression = New CodeDom.CodeParameterDeclarationExpression(fnIP.Value.ToString(), fnIP.Key.ToString())

I suspect that using a string to specify a native type is causing the DOM to believe this is a user-defined type 'int' and masks it with an @ to prevent the native int from being used. From https://en.wikipedia.org/wiki/C_Sharp_syntax#Keywords

If an identifier is needed which would be the same as a reserved keyword, it may be prefixed by the @ character to distinguish it

To make sure that the output uses a native type like int you could try using

new CodeTypeReference(typeof(int))

In other words, use a real Type with the public CodeTypeReference(Type type); constructor.

To get a real Type from a string naming the type, you can use the Type.GetType(String) function.

So try this:

New CodeDom.CodeTypeReference(Type.GetType(functionClass.FunctionNameAndType.Select(Function(fn) fn.Value)(0).ToString()))

and

parameterExpression = New CodeDom.CodeParameterDeclarationExpression(Type.GetType(fnIP.Value.ToString()), fnIP.Key.ToString())
Christopher Hamkins
  • 1,442
  • 9
  • 18
  • Thanks Christopher. For this to work I appended "System" Keyword and then tried to use Type.GetType("System" & fnIP.Value.ToString()), fnIP.Key.ToString()) Then it worked. – coding_cs Dec 15 '21 at 15:39