input: Write a function to convert a given Python program to a C# program. The function should accept the Python code as a string, parse it, and return the equivalent C# code as a string.
  
  assert convert_to_csharp("def power(x, y):\n    if y == 0:\n        return 1\n    else:\n        return x * power(x, y - 1)") == "public int Power(int x, int y)\n{\n    if (y == 0)\n    {\n        return 1;\n    }\n    else\n    {\n        return x * Power(x, y - 1);\n    }\n}"
  
  assert convert_to_csharp("def greet(name):\n    print(\"Hello, \" + name)") == "public void Greet(string name)\n{\n    Console.WriteLine(\"Hello, \" + name);\n}"
output: def convert_to_csharp(python_code):
      import ast
      class PythonToCSharpVisitor(ast.NodeVisitor):
          def visit_FunctionDef(self, node):
              return_type = 'void' if not node.returns else 'int'
              csharp_code = f"public {return_type} {node.name}({', '.join([f'{self.visit(arg.annotation)} {arg.arg}' for arg in node.args.args])})\n{{\n"
              for stmt in node.body:
                  csharp_code += self.visit(stmt) + "\n"
              csharp_code += "}"
              return csharp_code
  
          def visit_If(self, node):
              csharp_code = f"if ({self.visit(node.test)})\n{{\n"
              for stmt in node.body:
                  csharp_code += self.visit(stmt) + "\n"
              csharp_code += "}\n"
              if node.orelse:
                  csharp_code += "else\n{\n"
                  for stmt in node.orelse:
                      csharp_code += self.visit(stmt) + "\n"
                  csharp_code += "}\n"
              return csharp_code
  
          def visit_Return(self, node):
              return f"return {self.visit(node.value)};"
  
          def visit_Constant(self, node):
              return str(node.value)
  
          def visit_BinOp(self, node):
              return f"{self.visit(node.left)} {self.visit(node.op)} {self.visit(node.right)}"
  
          def visit_Add(self, node):
              return '+'
  
          def visit_Sub(self, node):
              return '-'
  
          def visit_Mult(self, node):
              return '*'
  
          def visit_Call(self, node):
              if node.func.id == 'print':
                  return f"Console.WriteLine({', '.join([self.visit(arg) for arg in node.args])})"
              return f"{node.func.id}({', '.join([self.visit(arg) for arg in node.args])})"
  
          def visit_Name(self, node):
              return node.id
  
          def visit_Str(self, node):
              return f'"{node.s}"'
  
          def visit_Num(self, node):
              return str(node.n)
  
          def generic_visit(self, node):
              raise NotImplementedError(f"Unsupported node type: {type(node).__name__}")
  
      tree = ast.parse(python_code)
      visitor = PythonToCSharpVisitor()
      return visitor.visit(tree)