Click here to Skip to main content
15,891,841 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm working on a code generator to generate several hundred c# class definition files from XML definitions. I'm writing the .cs files directly; I'm not using T4. (I really need to learn this.)
My question is:
How do I get the generated files to be included in the Visual Studio project to be compiled?

[Adding clarification:]
The generated code will be used in an existing project (like the .Designer.cs file behind the EntityFramework .edmx).
These classes will be used within the rest of this project.
I could have hand-generated the files but with so many (hundreds!), that would have been extremely tedious and error prone.
They will only need to be regenerated if the XML file changes. This is a low probablility, unless I discover an error in the XML (or generated code).
I don't need dynamic loading.

So far I've just been brute-force writing text to .cs files with the variations in the class definitions based on the info in the XML file.
(That was the quick way to go, vs. learning T4. I also thought about CodeDOM, but text output didn't require the learning curve.)

(Also, right now it is generating a .cs file for each class, but it could just as easily generate one big .cs file for everything, if that makes it easier to "hook into" the existing project.)
Posted
Updated 15-Nov-12 8:49am
v3

As an "experiment" I took 2 parts of my code generator and converted them to 2 T4 Text Templates.
(Converting from programmatically writing the code to using the T4 template is much easier than I expected. Without more experience, though, directly building the template seems like it would still be more difficult...no IntelliSense, no editor syntax error checking, etc.)

These files integrated directly into the build correctly.
However, they are "hard coded" to the source XML file, so Visual Studio still doesn't know that they should be regenerated on every build (like Entity does; actually Entity will even regenerate the .Designer.cs file if it is manually edited!)

I may still look at CodeDOM, but this seems to be a pretty good solution, if I can get "safer" regeneration.
 
Share this answer
 
I think the best way is to use the Visual Studio API, have a look at Extending Visual Basic and Visual C# Projects[^]

Best regards
Espen Harlinn
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 19-Nov-12 18:36pm    
In fact, very useful branch of project-related documentation, a 5.
--SA
Espen Harlinn 19-Nov-12 18:37pm    
Thank you, Sergey :-D
Probably, this problem should not be tied with Visual Studio. I mean, of course you can generate a project file and .NET even gives you a comprehensive API for using it. But, most likely, you should rather base your architecture on CodeDOM:
http://msdn.microsoft.com/en-us/library/650ax5cx.aspx[^].

Some background: everything you need for the development is actually bundled with .NET Framework, a freely redistributed thing. At least, you always have C#, VB.NET compiler, MSBuild and all the components to use them. That said, the user who installed .NET can always use assemblies compiled and loaded during run time by your application. Visual Studio is absolutely not needed for this purpose. This way, your possibilities are probably even better then you expected. The FCL (Framework Class Library) always provides you with the CodeDOM providers for these languages which you can use to generate assemblies, either temporary, of stored re-used permanently.

You also need to be able to understand and use Reflection:
http://msdn.microsoft.com/en-us/library/hh156524.aspx[^],
http://msdn.microsoft.com/en-us/library/f7ykdhsy.aspx[^].

Don't think that Reflection is too slow for this purpose. Yes, it is slow, but if you design things properly, its runtime use is reduced to minimum. Optimally, you can develop some statically bound interface(s). When you generate an assembly dynamically, Reflection is only needed to locate some type implementing the interface, instantiate it (get in in instance of a type/structure accessible through the interface reference), and you are done with Reflection part. When you got an interface reference representing the implementation type, you just use this interface, and through the interface members, you might access all other types in the dynamically generated assembly.

Please see my past answers on related topics, but keep in mind, that in some of those answers I discuss much more advanced matter than you might need, mostly related to Application Domains and a need of using IPC to work across the domains. You might not need it, so first focus on CodeDOM usage:
Create WPF Application that uses Reloadable Plugins...[^],
AppDomain refuses to load an assembly[^],
code generating using CodeDom[^],
C# Reflection InvokeMember on existing instance[^],
Gathering types from assemblies by it's string representation[^].

Your follow-up questions are welcome.

Good luck,
—SA
 
Share this answer
 
v3
Comments
Matt T Heffron 15-Nov-12 18:46pm    
As an "experiment" I took 2 parts of my code generator and converted them to 2 T4 Text Templates. (Converting from programmatically writing the code to using the T4 template is much easier than I expected. Without more experience, though, directly building the template seems like it would still be more difficult...no IntelliSense, no editor syntax error checking, etc.)

They're integrated directly into the build correctly. However, they are "hard coded" to the source XML file, so Visual Studio still doesn't know that they should be regenerated on every build (like EntityDoes; actually Entity will even regenerate the .Designer.cs file if it is manually edited!)

I may still look at CodeDOM, but this seems to be a pretty good solution, if I can get "safer" regeneration.

I'm voting this 4, since it is good advice, but not the actual solution I'm using.
Sergey Alexandrovich Kryukov 15-Nov-12 18:48pm    
Thank you. Whatever you want to vote (and what, you don't want to accept it formally, even if you won't use it? :-).., and I would be interested to see your solution. Is that possible if you share some information on it when you design and implement it?
--SA
Espen Harlinn 15-Nov-12 19:51pm    
I think it's well worth a 5 :-D
Sergey Alexandrovich Kryukov 15-Nov-12 22:05pm    
Thank you, Espen.
--SA
The files in your project are listed in the csproj file, which is XML. I am not sure if you can edit that on the fly if the project is already open, but that's where you'd need to do it, either way.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 15-Nov-12 14:24pm    
Not a good idea, most likely, by a number of reasons. Please look at my answer to see what I mean.
--SA
Christian Graus 15-Nov-12 14:25pm    
*grin* well, I knew some of the stuff you said, but it's clear you know more about this than me. It just seemed obvious to me that you could probably run the compiler outside the IDE with a list of files, but the easier thing to do would be to maintain the csproj file. The format looks simple enough, why is this an issue ? I guess you'd still be tied to VS for the actual compilation ?
Sergey Alexandrovich Kryukov 15-Nov-12 14:35pm    
Well, yes, strictly speaking, you are right -- MSBuild API is comprehensive and provides you with all one would need to create a project structure, very custom, universal, etc. So, even direct use of XML is not needed. The problem is -- MSBuild is more universal and indirect that it is needed; it supports incremental compilation based on time stamps -- well, you know all that -- and a lot more. The problem solved with MSBuild highly universal in terms of the build and more complex then it is required in the pretty much "usual" (I hope understand why "usual" is in quotes -- there is a lot of common stuff of code-generation based architectures, but such architectures are relatively esoteric) architectures.

Now, tied with VS for actual compilation? Not at all! And this is something important to understand. The actual build with C# and VB.NET does not need Visual Studio at all -- everything is bundled with .NET Framework itself. No need for Studio at all! (I can tell you, I started working with .NET before I has Studio of appropriate version.) C++ (C++/CLI) and other .NET languages is extra, of course.

--SA
Matt T Heffron 15-Nov-12 14:51pm    
Thanks Sergey.
I've added some "clarification" to the question. Does this change your recommendation?
Sergey Alexandrovich Kryukov 15-Nov-12 17:42pm    
We could better discuss it in the comments to my answer. In brief, you clarification does not make the decision more certain. CodeDOM actually does not assume dynamic loading. You just obtain some assembly, which can be in a permanent file. For your information, no matter how the assembly is loaded, CodeDOM build always create a "regular" assembly in a file, but it can be a temporary directory. In real life, CodeDOM just uses the usual compilers working with files and then loads assembly from file, the API is just abstracted from this detail.

Now, it looks to me that your code generation could be considered as a custom build step. If this is so, you better need to prescribe the build rules: you generate code, and use the assembly in other assemblies. Apparently, you would need to make other code depending on the project generating code. And now, it looks CodeDOM is still beneficial. First of all, you should better isolate generated code from other code. In particular, this is important to protect the developer from actually edited the generated code -- it's not a "real" source, and it should only be modified via modification of data use for generation of even generating code itself.

That said, using CodeDOM will be more consistent. Your generated files are really the intermediate stuff, but you generated assembly (assemblies) is really the final output, and you can even delete the generated files after generation, as all you need for further steps is in the compiled assembly and its matadata (importantly). Having this files in developer's project would be very much irrelevant.

Some details need thinking, but I think you can get a very smooth code life cycle, despite of considerable complications related to code generation. You see, I have worked quite well with code generation and can see some non very obvious implications, but code generation base architectures are relatively rare... Some detail might need consideration, but overall what I suggest looks like a good option.

--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900