Get all methods from C# source code - c#

I am looking forward to get all method names used in C# using following code:
CompilerParameters parameters = new CompilerParameters()
{
GenerateExecutable = false,
GenerateInMemory = true
};
var provider = new CSharpCodeProvider();
foreach (string path_file in files)
{
string source = File.ReadAllText(path_file);
Console.Out.WriteLine(source);
CompilerResults results = provider.CompileAssemblyFromSource(parameters, source);
if (results.Errors.HasErrors)
{
foreach (var error in results.Errors)
Console.Out.WriteLine(error.ToString());
return;
}
}
I am trying to read the source code in a variable source and passing this in CompileAssemblyFromSource method of CSharpCodeProvider class.
I am getting the following error under result variable.
c:\Users\username\AppData\Local\Temp\2rdqotiv.0.cs(3,14) : error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'System' (are you missing an assembly reference?).
Can anyone please help me to solve this error? I am using MVS 15.

You have to add the referenced assemblies, for example:
parameters.ReferencedAssemblies.Add(typeof(Enumerable).Assembly.Location);
You can also add assemblies manually, as follows:
string exDir = $#"C:\WINDOWS\Microsoft.NET\Framework\v{ver}";
parameters.CompilerOptions = $"/lib:{exDir}";
And BTW, you could also use CompileAssemblyFromFile instead of having to open the files manually.

Related

CSharpScript. DynamicClass as globals getting CS0234 error

I'm trying to build flexible script evaluator, which сould receive dynamic list of global variables.
I'm using DynamicClass from DynamicLinq lib for build global object. But I've got CS0234 error:
The type or namespace name 'Dynamic' does not exist in the namespace 'System.Linq'
My problem is that my global type instance generated dynamically, and I can't add dynamic assembly to references. InteractiveAssemblyLoader doesn't work too.
I know about DynamicExpression-s, but I'm trying to find pure solution.
var type = DynamicClassFactory.CreateType(
new List<DynamicProperty>()
{
new DynamicProperty("X", typeof(int)),
new DynamicProperty("Y", typeof(int))
});
var data = Activator.CreateInstance(type) as DynamicClass;
data.SetDynamicPropertyValue("X", 1);
data.SetDynamicPropertyValue("Y", 2);
using (var loader = new InteractiveAssemblyLoader())
{
loader.RegisterDependency(type.Assembly);
loader.RegisterDependency(typeof(ExpandoObject).Assembly);
var script = CSharpScript.Create<int>("X + Y",
ScriptOptions.Default
.AddReferences("System.Linq")
.AddReferences("System.Linq.Expressions")
.AddReferences("System.Linq.Dynamic.Core.DynamicClasses")
.AddImports("System.Linq")
.AddImports("System.Dynamic")
.AddImports("System.Linq.Dynamic.Core.DynamicClasses"),
globalsType: type,
assemblyLoader: loader
);
var t = script.Compile();
var p = await script.RunAsync(data);
}

CSharpCodeProvider "string" contains no definition for "Select". CSCC having problems with System.Linq

I'm trying to use CSharpCodeProvider to compile a piece of code.
The error is:
c:\...\crust.cs(551,48) : error CS1061: 'string' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)
The code being compiled is:
using System;
...
using System.Linq;
...
return new string(str.Substring(1).Select(character => (char)((character - 54545) ^ key)).ToArray());
...
The code compiling the source is as follows:
...
String exeName = String.Format("NAME.exe");
CompilerParameters cp = new CompilerParameters
{
GenerateExecutable = true,
GenerateInMemory = false,
OutputAssembly = "NAME.exe",
CompilerOptions = "/target:exe /platform:x64"
};
cp.ReferencedAssemblies.Add("System.dll");
...
cp.ReferencedAssemblies.Add("System.Linq.dll");
cp.GenerateExecutable = true;
cp.OutputAssembly = exeName;
cp.GenerateInMemory = false;
cp.TreatWarningsAsErrors = false;
CompilerResults cr = provider.CompileAssemblyFromFile(cp,
sourceName);
...
No other system.linq methods work either.
Notes:
Compiler is 64 bit
Source is being compiled in to 64 bit
Compiler is in .net framework 4.0
Source is being compiled in to .net 4.0
Maybe because you haven't declared using statment for 'System.Linq' package:
using System.Linq;
Check it out in the cs file and make sure the using statment is declared explicitly.

Creating a method at runtime and System.IO Exception

Hello I have been trying to figure this out for a while now and cannot get it correct. I have found a few threads that do similar to what I want to do. but I keep getting a system.Io Assembly cannot be found compile and run the string that was created.
private bool CalculateBooleanExpression(string expression)
{
var classExpression = stringClass.Replace(ReplaceMe,expression);
var complierParameters = new CompilerParameters()
{
GenerateExecutable=false,
GenerateInMemory = true
};
var complier = new CSharpCodeProvider();
var compilerResults = complier.CompileAssemblyFromSource(complierParameters, classExpression);
//break point here compilerResults.CompiledAssembly is null
object typeInstance = compilerResults.CompiledAssembly.CreateInstance("BooleanEvaluator");
MethodInfo methodInfo = typeInstance.GetType().GetMethod("Calculate");
bool value = (bool)methodInfo.Invoke(typeInstance, new object[] { });
return true;
}
Could not load file or assembly 'file:///C:\Users\james.tays\AppData\Local\Temp\22ozhhme.dll' or one of its dependencies. The system cannot find the file specified.
can anyone tell me how to debug this so i can figure out where there error is?
EDIT:
While debugging I have found this error too.
error CS0116: A namespace cannot directly contain members such as fields or methods}

Automatically resolving dependencies when compiling using Roslyn

I'm currently writing an application that currently loads a project via Roslyn's workspace API, turns a specified C# file into a syntax tree then creates an in memory assembly form it, then eventually extracts the IL.
This is all working fine, however as soon as I reference any external libraries within the said C# file, the compilation fails as Roslyn doesn't know where to resolve those references.
Here's a simplified version of what I'm currently doing:
MetadataReference[] metaDatareferences = {
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(Uri).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(DynamicAttribute).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(AssemblyMetadata).GetTypeInfo().Assembly.Location),
};
var sourceLanguage = new CSharpLanguage();
var syntaxTree = sourceLanguage.ParseText(sourceCode, SourceCodeKind.Regular);
var options = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Debug,
allowUnsafe: true
);
CSharpCompilation compilation = CSharpCompilation.Create("ExampleAssembly", options: options);
var stream = new MemoryStream();
var result = compilation.
AddReferences(metaDatareferences)
.AddSyntaxTrees(syntaxTree)
.Emit(stream);
// Success is false
if (!emitResult.Success)
{
foreach (var diagnostic in emitResult.Diagnostics)
{
Debug.WriteLine(diagnostic.ToString());
}
}
The output of the Debug.WriteLine is:
(1,7): error CS0246: The type or namespace name 'MediatR' could not be found (are you missing a using directive or an assembly reference?)
(9,32): error CS0246: The type or namespace name 'Mediator' could not be found (are you missing a using directive or an assembly reference?)
And the file my Roslyn project is reading is simply this:
using MediatR;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
var mediator = new Mediator(null, null);
}
}
}
My question is, does Roslyn provide an API for automatically load any dependencies a file may have? I was hopeful that the Roslyn workspace would allow this to be done, but I've not been able to find anything.
If the MediatR console project is a project.json project, then you can use ProjectJsonWorkspace from "Microsoft.DotNet.ProjectModel.Workspaces": "1.0.0-preview2-1-003177". You can point it at your project.json and get a Compilation object, this will have done all the hard work for you of getting the project references, file references, etc... Then you can just emit your IL from here.
Here is an example:
var compilation = new ProjectJsonWorkspace(#"PathToYour\project.json").CurrentSolution.Projects.First().GetCompilationAsync().Result;
var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
Or if you need total control, you could continue to use CSharpCompilation.Create, copying in what you need from the compilation object here, and passing in a SyntaxTree.
Hope that helps.

C# Loading assemblies dynamically

I'm having an issue when compiling text into dynamic objects at runtime.
I wrote a simple piece of code to compile the text:
public class CompileFactory
{
public dynamic Compile(String classCode, String mainClass, Object[] requiredAssemblies)
{
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string>
{
{ "CompilerVersion", "v4.0" }
});
CompilerParameters parameters = new CompilerParameters
{
GenerateExecutable = true, // Create a dll
GenerateInMemory = true, // Create it in memory
WarningLevel = 3, // Default warning level
CompilerOptions = "/optimize", // Optimize code
TreatWarningsAsErrors = false // Better be false to avoid break in warnings
};
// Add all extra assemblies required
foreach (var extraAsm in requiredAssemblies)
{
parameters.ReferencedAssemblies.Add(extraAsm as string);
}
CompilerResults results = provider.CompileAssemblyFromSource(parameters, classCode);
if (results.Errors.Count != 0)
{
return "FAILED";
}
return results.CompiledAssembly.CreateInstance(mainClass); ;
}
}
This is how I am using the Compile method.
List<string> assemblies = new List<string>{"System.Net.Mail.dll", "System.Net.dll"};
dynamic obj = compile.Compile(fileText, pluginName, assemblies.ToArray());
As you can see I'm adding references to extra assemblies at some point. For some reason when I add using System.Net; to the text file, it will not be referenced and I get errors. The text I'm compiling is literally a .cs file saved as text. I thought of working around this by extracting the using * and adding them separately, however for when adding System.Net.Mail.dll, the metadata file cannot be found.
Has anyone experienced something similar? I really would like to just add the using * to the file and be ready with it.
Any input would be greatly appreciated.
The issue here is that System.Net.dll does not exist. You can check in which assembly a .Net type is by right clicking somewhere it is referenced and choosing "Go to definition". This will bring up a tab with the class definition "from metadata". At the top of this file, you've got a #region showing where this type comes from. In the case of a TcpClient, we can see this:
#region Assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll
#endregion
Change your call to Compile with "System.dll" instead of "System.Net.dll" and it should work just fine
Edit/Clarification: It is not possible to get an assembly name from a using statement.

Categories

Resources