C# code expansion/injection in compile time - c#

I'm looking for a way to expand/inject code at compile time,
something like templates/macros/snippets...
Let's say I wrote this code in a lot of places in my application:
[JsonObject("MyProperty")]
private string MyPropertyJson { get; set; }
public object MyProperty { get; set; }
The MyPropertyJson property is used for EF mapping purposes only so I save the value is a JSON string in DB but for class users, they only know about MyProperty property.
What I want to do is, at compile time, MyPropertyJson to be expanded to this:
private string MyPropertyJson
{
get
{
return JsonConvert.SerializeObject(MyProperty);
}
set
{
MyProperty = JsonConvert.DeserializeObject(value);
}
}
I want this to be done in the output binaries only without affecting the source code.
I know about Unity, PostSharp, Aspect-Injector, etc.. but they don't achieve what I want because by using them, I have to use some reflection to find & manipulate MyProperty but I want to expand it exactly like it's been written in the same class with access to all class internals.
It's exactly like code snippets but to be expanded during compilation phase.

A solution that doesn't cost anything extra and is supported within Visual Studio is T4 aka Text Templates. However, it does require you install the VS SDK (eg, 2015) and Modeling SDK (eg, 2015) of the version of VS that you use.
For my base class libraries, I end up dedicating an assembly for utils to use in the T4 code I write in production code. I use it in places like rolling out read/writes for primitives in IO code (eg, .TT and .CS). Although you don't have to do this if you don't need much/complex compile time code gen.

I was able to achieve my requirement by writing a BeforeBuild msbuild target to call an external console app which I've developed to:
Copy source files that will be rewritten to a temp folder
Rewrite the source code in the temp files
Added conditional Compile tag to the .csproj file to include manipulated source files instead of the original ones
It works like a charm :)
I'm working on a generic engine for this task and will commit it to github once finished.

The is a way to kind of get what you want.
Using implicit operators
That would need to create your own json object class for example, then add these:
class JsonObject {
public object obj;
public static implicit operator string(JsonObject target) {
return Json.SerializeObject(target.obj);
}
}
But that won't really do what you really wanted. Almost the same as creating a new class and add functions.

Related

Unity/C# Savegame Migration

I've written a SaveLoad class, which contains a Savegame class that has a bunch of ints, doubles, bools but also more complex things like an array of self-written class objects.
That savegame object is being created, serialized and AES encrypted on save and vice versa on load - so far, so good.
The problem I'm facing now is that if there are new variables (in a newer version of the game) that have to be stored and loaded, the game crashes on load, because the new variables can't be loaded correctly (because they are not contained in the old save file). E.g. ints and doubles contain the default 0 while an array is not initialized, thus null.
My current "solution": For each variable that is being loaded, check if it doesn't contain a specific value (which I set in the Savegame class).
For example: In Savegame I set
public int myInt = int.MinValue;
and when loading, I check:
if(savegame.myInt != int.MinValue){
//load successful
}else{
//load failed
};
This works so far for int and double, but once I hit the first bool, I realized, that for every variable I have to find a value that makes "no sense"(not reachable usually), thus was a failed load. => Shitty method for bools.
I could now go ahead and convert all bools to int, but this is getting ugly...
There must be a cleaner and/or smarter solution to this. Maybe some sort of savegame migrator? If there is a well done, free plugin for this, that would also be fine for me, but I'd prefer a code-solution, which may also be more helpful for other people with a similar problem.
Thanks in advance! :)
Your issue is poor implementation.
If you are going to be having changes like this, you should be following Extend, Deprecate, Delete (EDD).
In this case, you should be implementing new properties/fields as nullables until you can go through and data repair your old save files. This way, you can check first if the loaded field is null or has a value. If it has a value, you're good to go, if it's null, you don't have a value, you need to handle that some way.
e.g.
/*We deprecate the old one by marking it obsolete*/
[Obsolete("Use NewSaveGameFile instead")]
public class OldSaveGameFile
{
public int SomeInt { get; set; }
}
/*We extend by creating a new class with old one's fields*/
/*and the new one's fields as nullables*/
public class NewSaveGameFile
{
public int SomeInt { get; set; }
public bool? SomeNullableBool { get; set; }
}
public class FileLoader
{
public SavedGame LoadMyFile()
{
NewSaveGameFile newFile = GetFileFromDatabase(); // Code to load the file
if (newFile.SomeNullableBool.HasValue)
{
// You're good to go
}
else
{
// It's missing this property, so set it to a default value and save it
}
}
}
Then once everything has been data repaired, you can fully migrate to the NewSaveGameFile and remove the nullables (this would be the delete step)
So one solution would be to store the version of the save file system in the save file itself. So a property called version.
Then when initially opening the file, you can call the correct method to load the save game. It could be a different method, an interface which gets versioned, different classes, etc but then you would require one of these for each save file version you have.
After loading it in file's version, you could then code migration objects/methods that would populate the default values as it becomes a newer version in memory. Similar to your checks above, but you'd need to know which properties/values need to be set between each version and apply the default. This would give you the ability to migrate forward to each version of the save file, so a really old save could be updated to the newest version available.
I'm facing the same problem and trying to build a sustainable solution. Ideally someone should be able to open the game in 10 years and still access their save, even if the game has changed substantially.
I'm having a hard time finding a library that does this for me, so I may build my own (please let me know if you know of one!)
The way that changing schemas is generally handled in the world of web-engineering is through migrations-- if an old version of a file is found, we run it through sequential schema migrations until it's up-to-date.
I can think of two ways to do this:
Either you could save all saved files to the cloud, say, in MongoDB, then change their save data for them whenever they make updates or
You need to run old save data through standardized migrations on the client when they attempt to load an old version of the save file
If I wanted to make the client update stale saved states then, every time I need to change the structure of the save file (on a game that's been released):
Create a new SavablePlayerData0_0_0 where 0_0_0 is using semantic versioning
Make sure every SavablePlayerData includes public string version="0_0_0"
We'll maintain static Dictionary<string, SavedPlayerData> versionToType = {"0_0_0": typeof(SavablePlayerData0_0_0)} and a static string currentSavedDataVersion
We'll also maintain a list of migration methods which we NEVER get rid of, something like:
Something like
public SavablePlayerData0_0_1 Migration_0_0_0_to_next(SavablePlayerData0_0_0 oldFile)
{
return new SavablePlayerData0_0_1(attrA: oldFile.attrA, attrB: someDefault);
}
Then you'd figure out which version they were on from the file version, the run their save state through sequential migrations until it matches the latest, valid state.
Something like (total pseudocode)
public NewSavedDataVersion MigrateToCurrent(PrevSavedDataVersion savedData)
{
nextSavedData = MigrationManager.migrationDict[GetVersion(savedData)]
if (GetVersion(nextSavedData) != MigrationManager.currentVersion) {
return MigrateToCurrent(nextSavedData, /* You'd keep a counter to look up the next one */)
}
}
Finally, you'd want to make sure you use a type alias and [Obsolete] to quickly shift over your codebase to the new save version
It might all-in-all be easier to just work with save-file-in-the-cloud so you can control migration. If you do this, then when a user tries to open the game with an older version, you must block them and force them to update the game to match the saved version stored in the cloud.

Most efficient way to move an inline class, interface, or enum to it's own file in Visual Studio

Sometimes when I'm developing I may prefer to quickly inline classes, interfaces and/or enums when I'm building a fresh design or from within a test fixture. However, I find it inconvenient to interrupt my thought process to create new code files, copy and paste the class/interface/enum written inline to the new file, and all the time it takes to navigate between them.
I'm looking for an extension, macro, or hidden shortcut combo that will automatically create a file for the highlighted or selected inline class/interface/enum, and, if possible, copy the using list so that it can be built (but remove & sort will clean it up later).
I'm open to extensions, macros, or hidden shortcut keys. Suggestions?
Edit #1: ReSharper looks awesome, yes, and it appears to have exactly what I need, but I would like to find a free solution, if it exists, that didn't push me back $200.
Edit #2: After your helpful input, I'm pushing for my dev team to all run the ReSharper trial, and re-evaluate in a few weeks if the value-add is worth it. We want keep our extension use consistent, so I'm hoping we all find it equally worthwhile.
Example: I want to turn this (IExample.cs):
using System.Linq;
public interface IExample
{
}
public class Example : IExample
{
}
public enum ExampleType
{
}
...into these:
IExample.cs:
using System.Linq;
public interface IExample
{
}
Example.cs
using System.Linq;
public class Example : IExample
{
}
ExampleType.cs
using System.Linq;
public enum ExampleType
{
}
The built in refactoring tools do not have a simple way to extract a class to its own file, so the simplest thing to do if you do not have a refactoring tool like Resharper or Refactor! Pro that do have it is to:
Copy the class to memory.
Add a new file with the class name.
Paste the class to the new file.
ReSharper offers the feature Move to another file to match type name, the ALT+Enter shortcut makes your work faster.
Devexpress Refactor!pro can be your solution....in example you posted, refactor! Pro shows a quick action menu at the bottom of the class name that you want to move.
In this Actionmenu there s the "Move to file" option that' s all you need....
EDIT:
Apparently, this method does move the type to its own file but still keeps the relationship with the previous class, so it won't actually change anything other than generate a seperate file. The type will still be nested in the same way.
This is a pretty old question and I just encountered the same issue.
In Visual Studio 2019 (and probably in 2017 as well, though I did not check),
you can select the entire class -> right click -> Quick Actions and Refactoring -> Move Type to its own file.
It correct all references to said type, too.
Very handy!

How to determine the code-file filename from a compiled application at runtime

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)

C# code generation

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?

What is the best way to implement versioning of a binary?

I am thinking of the following design:
static class AppVersion
{
public static string BuildDate
{
get; set;
}
public static string Version
{
get; set;
}
public static string GetVersion
{
get; set;
}
}
A few questions on this:
How can I get the build date?
How can I print a date in a nice format?
How can I obtain and print the Visual Studio version in a nice format?
It is probably a bad idea to hard code the version into the binary, so I put the version into assembly information. How can I programmatically get it?
I think your first questions are a matter of taste. You could use String.Format to get any style you want. Regarding your last question:
System.Reflection.Assembly.GetExecutingAssembly().Version
returns the version number of the current assembly and:
typeof(SomeTypeInSomeAssembly).Assembly.Version
will return the version number of the assembly containing the specific type.
We run all our production builds through CruiseControl.NET, which (among many other things) has the facility to version builds.
We then have a snippet of code that applies the CC.NET-generated build number (and other stuff) to AssemblyInfo.cs just before it's given to the compiler for building.
I suppose you could use a similar technique to insert the build date into a constant in some class somewhere in your app.
For build Date look at
http://dotnetfreak.co.uk/blog/archive/2004/07/08/determining-the-build-date-of-an-assembly.aspx
For the version / Get Version look at the System.Reflection.Assembly name space.
As for printing the date in a nice format, you'll want to either use the extension methods built off of DateTime class such as .ToShortDateString() or CultureInfo.
For build date or timestamp, you can embed it into the assembly when building.
For how to do that, see here.

Categories

Resources