1 - I have this file content on the disc (cs file, not compiled):
namespace Test
{
using System;
public class TestClass
{
public string SomeTestMethod(){
return "test here";
}
}
}
How do I get in run time into a variable the method:
public string SomeTestMethod(){
return "test here";
}
for example: SourceCodeParser.GetMothod("path to file","SomeTestMethod");
2 - Is it possible the content of accessor member?
public string SomeMember {
get {
return "test here";
}
}
Roslyn is what you need. You can easily install it using nuget. Here is a working code for getting a method body:
string GetMethod(string filename, string methodName)
{
var syntaxTree = SyntaxTree.ParseFile(filename);
var root = syntaxTree.GetRoot();
var method = root.DescendantNodes()
.OfType<MethodDeclarationSyntax>()
.Where(md => md.Identifier.ValueText.Equals(methodName))
.FirstOrDefault();
return method.ToString();
}
and code for getting body of property getter:
string GetPropertyGetter(string filename, string propertyName)
{
var syntaxTree = SyntaxTree.ParseFile(filename);
var root = syntaxTree.GetRoot();
var property = root.DescendantNodes()
.OfType<PropertyDeclarationSyntax>()
.Where(md => md.Identifier.ValueText.Equals(propertyName))
.FirstOrDefault();
var getter = property.AccessorList.Accessors.First(a => a.Kind == SyntaxKind.GetAccessorDeclaration);
return getter.ToString();
}
You need a tool that can parse the source code, tracks code locations, and knows how to look up methods (or variables, or whatever named thing you care about) in the source code. With that, finding the lines of interest is pretty easy. Such a tool isn't easy to build because parsers for full languages aren't easy to build. Nor are the lookup functions easy; parameters, namespaces, templates, inheritance all combine to make name lookup for modern languages remarkably complex.
Program transformation (PT) tools (which often have such full parsers already available) often do this by building an AST in memory which represents the code. Then, given rules for name lookup, finding the code in the AST by name is relatively straightforward, and one can use the prettyprinter function of such a tool to pretty print the named-entity into a buffer/string/diskfile wherever you want it parked.
You are not likely to find a PT as a subroutine you can call from C# directly. You may be able to invoke such a tool from your program, and have it return the string as a text result/in a file/via a pipe whatever you thinks is best for interprocess communication.
If you want to show the method text embedded in an HTML page, you can often configure the PT to generate the entire page containing the prettyprinted entity text. (See the JavaSource browser via my bio for an example like this).
The .NET Reflection class does not support decompiling to C#. The best you can do is use MMethodInfo.GetMethodBody() and call MethodBody.GetILAsByteArray() on the response. That will give you the MSIL which is the best that .NET reflection can give you.
To decompile to C# you will need a decompiler - of which there are at least a dozen legitimate options. You'll need to investigate for one that meets your requirements and budget.
One option is Red Gate's .NET Reflector. Nick Harrison has a long and thorough article on using .NET Reflector in an application to render source code as HTML.
Related
Is there such a thing as a LINQ Query Provider for querying C# files?
I have a Winforms app that I use to assist me in generating code as well as to supplement Visual Studio's editing capabilities for existing code. One thing I would like to be able to do is to query a given class to see if a method exists. Or query for a list of classes, or query for classes with a particular type in the method signature, etc.
Further, I would love to be able to run the usual CRUDs on said C# files, but I realize that this may be out of scope for this question.
SOLVED!
Thanks to the folks who suggested Roslyn, and especially thanks to the code sample provided by Konrad Kokosa below, I was able to get exactly what I needed.
First thing you need to do is download the Roslyn DLLs (I used NuGet). Then query away. Here is another example for getting an alphabetized list of all methods in a class:
static List<string> GetMethodList(string filename, string className)
{
var syntaxTree = SyntaxTree.ParseFile(filename);
var root = syntaxTree.GetRoot();
var #class = root.DescendantNodes().OfType<ClassDeclarationSyntax>().FirstOrDefault(md => md.Identifier.ValueText.Equals(className));
return (List<string>) #class.DescendantNodes().OfType<MethodDeclarationSyntax>().ToList().OrderBy(m => m.Identifier.ValueText).Select(m => m.Identifier.ValueText);
}
I've found Roslyn very intuitive. Here is an example of parsing source file for a specified methodName within specified class className:
static void GetClassMethod(string filename, string className, string methodName)
{
var syntaxTree = SyntaxTree.ParseFile(filename);
var root = syntaxTree.GetRoot();
var #class = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(md => md.Identifier.ValueText.Equals(className))
.FirstOrDefault();
var method = #class.DescendantNodes()
.OfType<MethodDeclarationSyntax>()
.Where(md => md.Identifier.ValueText.Equals(methodName))
.FirstOrDefault();
}
From this example you can easily build querying all classes withing a file.
Microsoft is working on a project called Roslyn which allows you to interact with C# code via ordinary .NET objects:
http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx
It hasn't been officially released, though, and I'm honestly not sure that it would include things like manipulating the source files (for example, to add a function to a class).
If you're working with code that is already compiled, you could probably use a combination of a few tricks, such as loading an assembly at runtime and then using reflection to interrogate it.
However, I would suggest taking a look at tools that are already available for generating code, like T4 Templates. There might be a better way to solve the underlying problem than interrogating C# source files.
I'm looking to implement some templates in a web application and wanted to utilize ASP.NET's templated controls. However, I don't want to rely on physical .ascx files, or the VirtualPathProvider in order to Load the templates.
I want to be able to load the templates from a database or other datastore (in memory?). Is there any implementation of a LoadTemplate() method that returns an ITemplate given a string representation of an .ascx template?
If not, how would I go about writing one?
FYI, Kentico has a similar feature, but they rely on the VirtualPathProvider in order to use the LoadTemplate() on the TemplateControl class. With that method, they are able to load templates (they call them transformations) stored in the database.
Yes, VirtualPathProvider is probably the method you will want to use, if a string or database is the source you want to use. (There are also code generators that can emit code, but usually those are used when building the code dynamically--not loading from an external source as in your case.)
You don't mention why you don't want to use the VirtualPathProvider though. Is it due to not wanting to, or can't because of some special requirements you have in a particular situation?
Finally, if it "seems trivial" to load and compile code dynamically, then you don't know what all the whole .Net system has to do before it can run dynamic code--assembly generation, compilation and JIT, application contexts, class/member name resolution, code security, etc. Maybe you've just been spoiled with how easy .Net has made doing other complicated tasks. ;-)
I've been facing a similar problem. However, the VirtualPathProvider is just too much plumbing to implement for such a small gain - not to mention that it seems like it has the potential to be a bit risky security-wise to implement. I've found two possible work-arounds:
1) Use reflection to get at what you want:
var page = HttpContext.Current.Handler as Page;
string text = "<table><tr><td>Testing!!!</td></tr></table>";
var systemWebAssembly = System.Reflection.Assembly.GetAssembly(typeof(Page));
var virtualPathType = systemWebAssembly.GetTypes().Where(t => t.Name == "VirtualPath").FirstOrDefault(); // Type.GetType("System.Web.VirtualPath");
var createMethod = virtualPathType.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(m => m.Name == "Create" && m.GetParameters().Length == 1).FirstOrDefault();
object virtualPath = createMethod.Invoke(null, new object[]
{
page.AppRelativeVirtualPath
});
var template = (ITemplate)typeof(TemplateParser).GetMethod("ParseTemplate", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).Invoke(null, new object[]{text, virtualPath, true});
2) Use a somewhat hacky work-around:
var page = HttpContext.Current.Handler as Page;
string text = "<table><tr><td>Testing!!!</td></tr></table>";
string modifiedText = string.Format("<asp:UpdatePanel runat=\"server\"><ContentTemplate>{0}</ContentTemplate></asp:UpdatePanel>", text);
var control = page.ParseControl(modifiedText);
var updatePanel = control.Controls[0] as UpdatePanel;
var template = updatePanel.ContentTemplate;
I openly admin that neither is a great solution. Ideally, there would be a method in the .Net Framework for this sort of thing. Something like:
public class TemplateParser
{
public static ITemplate ParseTemplate(string content, string virtualPath, bool ignoreParserFilter)
{
return TemplateParser.ParseTemplate(string content, VirtualPath.Create(virtualPath), ignoreParserFilter);
}
}
That would alleviate the whole need to implement the VirtualPathProvider. Maybe we'll see that in ASP.NET vNext :-)
Let's say I have an application with two files.
Console.cs and Business.cs
Console.cs has program Main class.
Business.cs has three classes named Customer, Order and Orderline.
Is there anyway in C# to determine at runtime (maybe with reflection) that the business objects are in a file named Business.cs?
The C# compiler does not emit this information into the DLL, so it's not available through reflection. However, as you'll be aware from debugging, the debugger can match up compiled locations to source code locations. It does this through PDB files. So it might be theoertically possible for you to ship your PDB files, and invoke the unmanaged debugger or diagnostic symbol store API (see General Reference > Unmanaged API Reference in MSDN) to determine where a given method was defined. You can't really do this for a class, though, because a class could be spread across multiple files using partial classes.
If you compile in debug mode you can probably use Cecil (part of Mono project) to extract the source filenames from the debug symbols. But when you compile in release mode this information probably gets lost.
However, if you need to do this, for other purposes than for example static analysis of your software, you are probably on the wrong track and should think of another solution.
If you put the classes in a Business namespace you could use reflection to find if an object comes from that namespace:
namespace Business {
class Customer {}
class Order {}
class OrderLine {}
}
var myObject = new Customer();
Console.WriteLine(myObject.GetType().Namespace); // writes "Business"
I believe the closest you'll get is typeof(Customer).Assembly.Location. However, this will only give you the DLL, not the location of the source code (which makes sense, since the source code would normally not be included with the binaries).
*.PDB (debug info files) files should have that information. Otherwise I see no way to get it, since code files is just an abstraction which compiled code should not care about.
not sure what your use case is, however if some one is calling you then you can add
compiler directives
[CallerFilePath] string file = "", [CallerLineNumber] int LineNo = 0
in your method.
if not than your best way of accessing this is by using the .pdb file that get's generated. The format is published and a C++ dll is available that can be used to access the file however the easiest way to read the file (and possible line number) if included in the pdb file is using stacktrace
You can access the stack in an exception, so if a class allows you to throw an exception by passing null where you should not than try catch it and you have your stack trace.
if you need the calling file but do not want to add the compiler directives as some one can simply overwrite it you can do something like:
StackTrace st = new StackTrace(new StackFrame(1));
st.GetFrame(1).GetFileName());
Assuming :
You have a project (probably technical with some extension methods etc) that all other projects in your solution reference (let's name it "NameSpaceGloballyVisibleByAllProjects")
You are using SDK-style csproj for your project (otherwise you'll have a little more work)
People in your team code without doing fancy things (ie: "class" / "struct"/ "enum" keywords are at the beginning of their own line in your .cs files).
It means that, by adding this class in "NameSpaceGloballyVisibleByAllProjects":
using System;
using System.Runtime.CompilerServices;
namespace NameSpaceGloballyVisibleByAllProjects
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]
public class MemorizeFilePathAttribute : Attribute
{
public string Path() { return _filepath; }
public MemorizeFilePathAttribute([CallerFilePath] string filepath = "")
{
_filepath = filepath;
}
readonly string _filepath;
}
}
You can simply use it like this:
using System.Reflection;
using NameSpaceGloballyVisibleByAllProjects;
Type type = typeof(Program);
var files = type.GetCustomAttributes<MemorizeFilePathAttribute>(false).Select(att => att.Path).ToList();
Note: As you notice there are more than one file! This is because of "partial" keyword in C#. So it's up to you to use "files.Single()" or not...
We just need to add this attribute above all types now
We can do that in Visual Studio with Ctr-H (Find-and-Replace).
Select All Solution
Check options "regex" & "case sensitive"
Find: "^( *)([a-z][a-z ]*)? (class|struct|enum) "
(without double quotes, but with the final ' '!)
Replace by: "$1 [NameSpaceGloballyVisibleByAllProjects.MemorizeFilePath]\r\n$1$2 $3 "
(without double quotes, but with the final ' '!)
Be ready for this to take a little time (Go get a coffe... or tea)
Interesting question here: In my current project we're using a custom performance monitoring suite that is very config-heavy (it uses Perfmon so we have to manually register each performance counter. There is one performance counter for each method that we monitor, and there are a lot of those).
I was wondering if there are any tools that would, say, allow me to analyse the project assembly, find all methods that instantiate an instance of class XClass, then write them out to a file? This would allow me to cut down the amount of manual config I need to do by a large margin.
Thanks, Ed
EDIT
Sorry, the 'write them to a file' thing was a little contrived: really I need to reformat them with some extra data and write them in a config-specific XML format. This would be best if I can code it up so it can be set as a build task (so I don't have to run it manually) and any future changes can be made easily and documented etc.
Open the assembly in Reflector (the free version is fine); find the type (F3), then bring up the anaylyzer (Ctrl+R) and expand the "Instantiated By" node.
Then right-click on the "Instantiated By" node itself and click copy; for example:
System.Data.SqlClient.SqlConnectionStringBuilder
Depends On
Used By
Exposed By
Instantiated By
SqlDependencyProcessDispatcher.GetHashHelper(String, SqlConnectionStringBuilder&, DbConnectionPoolIdentity&, String&, String) : SqlConnectionContainerHashHelper
System.Data.SqlClient.SqlClientFactory.CreateConnectionStringBuilder() : DbConnectionStringBuilder
System.Web.Management.SqlWebEventProvider.Initialize(String, NameValueCollection) : Void
System.Web.SessionState.SqlSessionStateStore.CreatePartitionInfo(String) : IPartitionInfo
System.Web.SessionState.SqlSessionStateStore+SqlPartitionInfo.get_TracingPartitionString() : String
System.Web.SessionState.SqlSessionStateStore+SqlStateConnection..ctor(SqlPartitionInfo, TimeSpan)
If you need to write code to automate your task, it's easy to do it with Mono.Cecil. As an example, this code searches through all the methods of the top level types of an assembly for the instantiation of a class Foo.Bar.Baz:
using Mono.Cecil;
using Mono.Cecil.Cil;
// ...
static void SearchMethod (MethodDefinition method)
{
foreach (var instruction in method.Body.Instructions) {
if (instruction.OpCode != OpCodes.Newobj)
continue;
var constructor = (MethodReference) instruction.Operand;
if (constructor.DeclaringType.FullName != "Foo.Bar.Baz")
continue;
Console.WriteLine ("new Foo.Bar.Baz in {0}", method.FullName);
}
}
static void Main ()
{
var module = ModuleDefinition.ReadModule ("Foo.Bar.dll");
var methods = module.Types.SelectMany (t => t.Methods).Where (m => m.HasBody);
foreach (var method in methods)
SearchMethod (method);
}
Take a look at NDepend. It's a static analysis tool with a very powerful query language: CQL (Code Query Language).
Update
NDepend has a console application that can be prodded for automation (e.g. for use in a build systems) and can output reports to file.
An example query to find methods which instantiate a defined type:
SELECT METHODS WHERE CreateA "MyNamespace.MyClass"
You probably want to change your design so that they use a factory instead, such that the factory is responsible for the extra bookkeeping.
That said, you can look in the System.Reflection namespace, (from memory), where the Assembly class is used.
i'm about to make a graduation project application
this application is gonna some way receive a description for a situation , and then accordingly generate c# code
i want to know in what field i need to search or how to autogenerate C# code
Have a look at Kathleen Dollard's book on this if you can. She has a website for this topic as well.
You have three options essentially:
Brute-force - creating the code files yourself in a text file
CodeDOM generation - MS's built in way of creating code.
XSLT - What Kathleen uses.
T4 templates can help too -
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
And you could also generate IL on the fly. ;)
CodeDOM
I've done a wrapper around codedom. You only need to create your own C# script and specify the types being used.
Example
public interface IWorld
{
string Hello(string value);
}
string code = #"namespace MyNamespace
{
class Temp : IWorld
{
public string Hello(string value)
{
return "World " + value;
}
}
}";
Compiler compiler = new Compiler();
compiler.AddType(typeof(string));
compiler.Compile(code);
var obj = compiler.CreateInstance<IWorld>();
string result = obj.Hello("World!");
Note that it was a long time ago that I wrote it. The example might not work 100%. (The Compiler class do work, the example might use it incorrectly).
Compiler source code: http://fadd.codeplex.com/SourceControl/changeset/view/65227#925984
Reflection.Emit
You can also generate IL using Reflection.Emit: http://msdn.microsoft.com/en-us/library/3y322t50.aspx
It's a bit harder but more flexible, since CodeDOM generates a new Assembly each type you compile code.
There is a set of MatLab tools that generates C/C++ code from state-charts and data-flow diagrams:
Real Time Workshop
Real-Time Workshop Embedded Coder
Stateflow Coder
You should dig into it.
What will be the "description of a solution" in your case?