Is it possible to construct an object by reading source code? - c#

Background
I have a few scripts that run as part of my build process that look at the various source code files and generate some more source code for me.
The scripts use CodeDom to generate them and they read the .cs files using a simple text reader.
Question
One of the scripts is looking for use of a specific class attribute called PageMenuItem and its purpose is to build a static list of page menu items.
It does this right now by reading all of the .cs files and looks for "PageMenuItem" attributes, then it counts the number of arguments and tries to figure out which constructor is being used so it can pull apart the various pieces of information.
There are 7 constructors for PageMenuItem with various parameters, so it is getting very difficult to determine from the .cs source code which constructor is being used and therefore how to parse out the information.
Instead of trying to parse the text myself, I would like to simply construct a PageMenuItem object in memory and then use its properties.
So, I need a way of taking the attribute declaration from the .cs file and construct a new instance of PageMenuItem from it.
Is that possible?
Another way of asking this question:
Given this string:
string myCodeStatement = "[MyAttribute(\"asdf\", \"foo\")]";
How can I create an object of the type MyAttribute so that I can work with that object? I have full access to the source code that defines MyAttribute.

Seems like you could introspect the class files, or alternately add an annotation to the constructor that would make your parsing job simpler. Aspect oriented techniques might help -- capture every time that constructor is called, and as it is, add the item to your list.

You can use the CSharpCodeProvider to do this. There is a Microsoft Support article describing the process.

Is invoking the compiler an option? You could build the source files themselves and use reflection to walk the attributes, or you could create a dummy source file that you mark up with those attributes. Either way, once it's compiled, you can reflect in to access the attribute's properties.

This script is part of the build process, so it needs to be pretty quick. Also, it generates source code that is going to get compiled, so I want to avoid "double compiling" my project.
I also don't want to have to compile and load an assembly just to reflect against it, which seems "expensive" to do several hundred times during my build process.
I decided that I just needed to fix up how I am parsing the attributes now. ---
I'm already reading the source code and trying to count the number of attributes. I decided I could modify that code to just parse the arguments into their types and then use Activator.CreateInstance() using my parsed arguments. Activator will figure out which constructor to use and I will get an instance of my attribute class and can use its properties.
I already know which types are available in the attribute's constructor, so I wrote a little method that parses the stuff between the parans into their correct type (string, int, guid, etc) and then I pass that object array to the Activator.
The Activator does the hard work of finding the correct constructor and gives me back an instance of my attribute class.

Related

How to parse source code fragment to System.Type

I have a set of strings like this:
System.Int32
string
bool[]
List<MyType.MyNestedType>
Dictionary<MyType.MyEnum, List<object>>
I would like to test if those strings are actually source code representations of valid types.
I'm in an environment, that doesn't support Roslyn and incorporating any sort of parser would be difficult. This is why I've tried using System.Type.GetType(string) to figure this out.
However, I'm going down a dirty road, because there are so many edge cases, where I need to modify the input string to represent an AssemblyQualifiedString. E.g. nested type "MyType.MyNestedType" needs to be "MyType+MyNestedType" and generics also have to be figured out the hard way.
Is there any helper method which does this kind of checking in .Net 2.0? I'm working in the Unity game engine, and we don't have any means to switch our system to a more sophisticated environment with available parsers.
Clarification
My company has developed a code generation system in Unity, which is not easily changed at this point. The one thing I need to add to it, is the ability to get a list of fields defined in a class (via reflection) and then separate them based on whether they are part of the default runtime assembly or if they are enclosed within #if UNITY_EDITOR preprocessor directives. When those are set, I basically want to handle those fields differently, but reflection alone can't tell me. Therefore I have decided to open my script files, look through the text for such define regions and then check if a field is declared within in them, and if true, put it in a separate FieldInfo[] array.
The one thing fixed and not changeable: All script will be inspected via reflection and a collection of FieldInfo is used to generate new source code elsewhere. I just need to separate that collection into individual ones for runtime vs editor assembly.
Custom types and nested generics are probably the hard part.
Can't you just have a "equivalency map to fully qualified name" or a few translation rules for all custom types ?
I guess you know by advance what you will encounter.
Or maybe run it on opposite way : at startup, scan your assembly(s) and for each class contained inside, generates the equivalent name "as it's supposed to appear" in your input file from the fully qualified name in GetType() format ?
For custom types of other assemblies, please note that you have to do things such as calling Assembly.LoadFile() or pass assembly name in second parameter to GetType() before to be able to load them.
See here for example : Resolve Type from Class Name in a Different Assembly
Maybe this answer could also help : How to parse C# generic type names?
Could you please detail what is the final purpose of project ? The problem is a bit surprising, especially for a unity project. Is it because you used some kind of weird serialization to persist state of some of your objects ?
This answer is more a few recommandations and questions to help you to clarify the needs than a definitive answer, but it can't hold in a single comment, and I think it provide useful informations

How can I get a list of every assembly, namespace, and class resolved through reflection in my application?

I need to use a iOS build setting in Unity3d that strips unused classes from bytecode but as it uses static analysis to discover which to remove- so any classes resolved through reflection will not be excluded from removal unless explicitly added to an exclusion list. I managed to remove all uses of reflection in my own code, but Mono itself seems to use a reflection based configuration to do a bunch of stuff and I've already added about a dozen classes to the exclusion list but now I'm to the point where exceptions are not giving any clues as to what class needs to be excluded for them to work.
My question is, is it possible to get a precise list of all the classes (with source assembly and namespace) resolved through reflection throughout every assembly that the application uses, and how would you go about it? I have Visual Studio 2012 and while I know it has powerful debugging tools I don't know how I would use them to this end.
Thanks.
The short version
You can't as there is no way to find all lookups via reflection using static analysis.
The long version
Just think of the following example: I write code that selects a class depending on user input, e.g. in pseudo code:
string action = ... ; // get some user input here, e.g. "Fire"
string clazz = "Do" + action;
var obj = Activator.CreateInstance("MyActions", clazz);
As you can see the actual full class name is not occuring anywhere in the code. So you would need to execute the code in every possible way to find out which values the clazz variable could assume. Therefore you cannot find out which classes this code would access via reflection.
Further Questions
What exact API from Mono are you using and what kind of exceptions are you getting? Maybe there is some alternative that could be used for your purpose.

Save and restore type (not object) created at runtime?

Inside our application (C# - .NET 4.5) we have a report generation tool. This tool must receive only the SQL command, verify it and from that, create a whole new report with available fields with the same name as specified by the SQL command and corresponding data types, similar to what an ORM tool would do.
Because of the nature of this tool we're using Reflection and Emit to create a whole new class. From fields provided by a dataReader (System.Data.SqlClient.SqlDataReader) we can create the type and populate it with the corresponding data.
The result of this is a IQueryable object that I can use on my reports.
This whole process is done and tested but to keep both the report, the generated class and the SQL command together we need to save this new type on the database and because or our database layout and system definitions, this requires me to provide an XML-like file or string to a method that will compress and convert to a Base64 string before saving it.
It would be a simple task if I were to save the report into a DLL file, just like shown HERE.
But since this new type must be transformed into an XML-like format I'm a little bit lost in here.
I have done the opposite on the past: fully create a type from an pure XML file, manually. I also know that I can do something similar but it would require me to loop into every detail/property/method/member/etc of the class to create the XML file.
Is there any way (like a helper from .NET framework) that could help me here?
Instead of doing it 100% manually I'd like to delegate the XML generation/parse to a tool probably with a better perforance too...
Edit:
People, READ THE TITLE BEFORE POSTING COMMENTS! I'm trying to save an XML for the type. TYPE. Not the object. The type.
#Mark Gravell
Thanks for the tip. I'll check that.
But about the schema: any way to save/load it automatically?
For saving the type, I would say either simply store the schema, and re-create a compatible type at runtime, or just use AssemblyBuilder etc and configure the dynamic-assembly as saveable, and write it as a .dll to disk (or elsewhere). Then just load the .dll at runtime and find the type. Either approach can work. If you already have the code to create a Type from a schema, the first may be easier.
For saving the data, my first instinct would be XmlSerializer, however that works via Assembly generation, so it might not like working against a fully-dynamic Type, from TypeBuilder. If XmlSerializer isn't happy, you could try protobuf-net; that also works in-memory (by default), so should be pretty happy.
However! I should note that you might also want to consider simply using a DataTable. While I don't have tons of love for DataTable, it is designed for exactly this scenario:
it can model fields that are defined only at runtime
it has inbuilt serialization of both schema and data
it implements the ComponentModel APIs for declaring runtime-models
which means most tools work with it for free

How to implement Global Strings C#

I have lots of global read only strings (around 100) that I am using in my application that will never change. I have been trying to think of the best solution that is easy to code and doesn’t have too much impact on performance. I need the strings to be used throughout the application like the example below, where Relationship is just a category in which the value is grouped and Alternate is the string value itself.
Relationship.Alternate
I have thought of creating static classes with static read only fields, static classes with const fields, implementing a Singleton pattern and even creating and parsing enums in a helper method. Can anybody provide some good advice on the best way to tackle this problem.
How about using resource files?
They are typed, easily accesible from your code at run-time, easily editable without need to recompile, and support any string content (i.e. not like enums, which only support identifier-like strings).
For example, you can add a resource file named GlobalStrings.resx to your C# project, and then add a string named Relationship_Alternate to that file. You can type any value you want for that string. In code, you would access the string value as:
GlobalStrings.Relationship_Alternate
Since those are identifiers validated at compile-time, you can guarantee that all your strings will load successfully at run-time.
Hope it helps.
Why dont u put them in enum which can make it memory efficient as well as readable along with less error prone
if they are going to be set at compile time you can try putting them in appSettings (in your web.config or app.config). This would typically apply for connection strings etc. If they are going to be set at run time, depending on some other value, you can go with static class & static read only fields
Edit:If you want them strongly typed, you can also use settings file . see MSDN article
You should consider using a resource file. See MSDN or solution B in this CodeProject article.

How to find amount of parameters in a constructor

I'm trying to find a way to determine how many parameters a constructor has.
Now I've built one constructor with no parameters and 1 constructor with 4 parameters.
Is there, in C#, a way to find out how many parameters a used or given constructor has?
Thing is, I'm using a third constructor to read log files. These logs files are read as string[] elements and there should be just as many as there are arguments. If not, I have a corrupt log file.
But I'm using a lot of subclasses and each constructor has more parameters for their specific log-type.
So I wanted to know: is there a method to check the amount of parameters on a constructor?
And yes, this is a school assignment. I don't know what terms to look for really, so the VS2008 object browser is currently not of much use.
You should look at the System.Reflection Namespace. More specifically, you can get a list of the constructors of a class with:
System.Type.GetType("MYClassName").GetConstructors()
It sounds as if you need to re think your code a bit. From your description, having to dynamically determine the number of arguments in a constructor sounds a bit hairy. You might consider a factory design pattern since the type of object created is determined at runtime. If I misunderstand your problem then using reflection as pointed out by other answers will do the trick for you.
i'm not sure exactly what context you need this information, but if you need it dynamically at run-time try the System.Reflection namespace
otherwise the Intellisense drop-list should show you all the constructors available...
The amount of parameters is constant. I've defined them and they're not changing.
What's happening is I'm simulating a sort of publications tree and I'm making divisions in that(a.k.a. subclasses)
Thusly, all the constructors of my subclasses have the parameters or the classes they inherit from.
Thusly, the length is different for each type of publication.
I have a third constructor, just in case I need to visualise my publication data throuhg reading the log file.
But I have to take into account that the log file might be corrupt. Which includes the possibility that there is no data for all my parameters in the log file.
This is why I have to know how to find the amount of parameters in my constructor: I have to check howmuch data there is in my log compared to the amount of parameters I have.
Can't you make a constructor that takes a reference to the log file (or the current raw logfile entry), reads it, and throw an error if there's any problem?
I'm trying to understand why you'd need to look at the number of elements a constructor has. It seems a weak design from what I've seen so far to trust that the number of elements in the log file happens to identify the type of publication to create.
The short answer to your immediate question is what was stated in an earlier answer: reflect on the constructor for the class you're trying to create, and examine its parameters.

Categories