Technically, the title of this article should be System.Linq.Expressions.Expression to LINQ C# syntax formatter but that’s a bit lengthy.
To get right to the point, I’ve developed a class to parse an Expression tree generated by a LINQ IQueryable query and produce C# LINQ syntax as output. I tried searching the internet for similar work and nothing was immediately available or that was in source form for me to integrate with my tool. So, I wrote my own.
Here’s some sample output from the class:
// C# LINQ query:
var query =
from x in (
from ea in TableA
join et in TableB on ea.TableBID equals et.TableBID
join es in TableC on ea.TableCID equals es.TableCID
join st in TableD on ea.TableDID equals (int?)st.TableDID
join sf in TableE on ea.TableEID equals (int?)sf.TableEID
join eb in TableF on ea.TableFID equals eb.TableFID
join psf in TableF on ea.PreviousTableFID equals (int?)psf.TableFID into temp from ps in temp.DefaultIfEmpty()
select new { ea = ea, et = et, es = es, st = st, sf = sf, eb = eb, ps = ps }
)
where ((x.ea.DueDate < (DateTime?)DateTime.Now.Date) && (x.es.Code != "C"))
select x
.OrderBy(a => a.ea.DueDate)
.Skip(20)
.Take(10);
This class is intended primarily for display purposes. It should not be used in its current state for attempting to write out compilable C# LINQ syntax.
Download the code:
I’ve been developing a LINQ-to-SQL auditing web-based tool for the last few days and I’d like to share some progress with you all.
This auditing tool takes an instance of our data repository implementation class, finds all public methods via reflection, and executes them one-by-one with a special auditing mode enabled. Each of our query methods is required to call one of our various audit methods depending on the query execution scenario. For instance, if enumeration over an IQueryable is needed to pull back multiple results, call AuditEnumerable(query) on that query. If a stored procedure needs to be executed, call AuditStoredProcedure(db => db.MethodToCallProcedure(prm1, prm2)). If you need a single result, either null or an instance, call AuditSingle(query).
Needless to say, all of our data repository methods have been made to follow development patterns such that no query execution is performed while in auditing mode. Conversely, if the auditing mode is turned off, the methods should behave as normal and return actual data from a connection to SQL Server.
This web page is deployed as a single aspx file with no code-behind for “mobility” purposes. It is currently deployed, for better or worse, in our internal WCF ASP.NET services host project right next to our *.svc files that host the service responsible for connecting to our data repository methods. The nice thing is that this tool is zero-configuration and Just Works (TM). It is contained all in one file and can be deployed virtually anywhere in any environment.
The main interface for the tool is a paged listing of our data repository methods and the auditing output per each method. An example:
-- This is a PAGING implementation. DECLARE @p0 int; DECLARE @p1 int; DECLARE @p2 int; DECLARE @p3 int;
SET @p0 = 777; SET @p1 = 778; SET @p2 = 20; SET @p3 = 10;
SELECT [t8].[StudentID], [t8].[bci_PrimaryEmail4] AS [BciPrimaryEmail4] FROM ( SELECT ROW_NUMBER() OVER (ORDER BY [t0].[DueDate]) AS [ROW_NUMBER], [t0].[StudentID], [t7].[bci_SSN] AS [bci_SSN4] FROM [dbo].[ei_Activity] AS [t0] INNER JOIN [dbo].[ei_ActivityType] AS [t1] ON [t0].[ActivityTypeID] = [t1].[ActivityTypeID] INNER JOIN [dbo].[ei_ActivityStatus] AS [t2] ON [t0].[ActivityStatusID] = [t2].[ActivityStatusID] INNER JOIN [dbo].[ei_Student] AS [t3] ON [t0].[StudentID] = ([t3].[StudentID]) INNER JOIN [dbo].[ei_Staff] AS [t4] ON [t0].[StaffID] = ([t4].[StaffID]) INNER JOIN [dbo].[ei_Staff] AS [t5] ON [t0].[EnteredBy] = [t5].[StaffID] LEFT OUTER JOIN ( SELECT 1 AS [test], [t6].[StaffID], [t6].[bci_FirstName], [t6].[bci_LastName], [t6].[bci_MiddleInitial], [t6].[bci_Suffix], [t6].[bci_PrimaryEmail], [t6].[bci_SSN] FROM [dbo].[ei_Staff] AS [t6] ) AS [t7] ON [t0].[PreviousStaffId] = ([t7].[StaffID]) WHERE ([t0].[StaffID] = @p0) AND ([t0].[ActivityTypeID] = @p1) ) AS [t8] WHERE [t8].[ROW_NUMBER] BETWEEN @p2 + 1 AND @p2 + @p3 ORDER BY [t8].[ROW_NUMBER]; GO
This is only a part of the output of the tool so far. I’ve also trimmed some of the more sensitive information from the query. I blogged about the SQL syntax highlighter I developed in my previous post so if you’re curious how I did that go back one post from here.
The method names in the listing page are enabled as hyperlinks to go into a “details” mode. In this details page, you can actually fill in parameter values (and properties found on classes for those parameter types) used to alter the generated SQL query. You can even Execute the method with your parameters and see the resulting output formatted as XML.
We’ve enabled all of our domain models that our data repository methods work with to be [DataContract] decorated. This gets us the ability to serialize these objects into whatever format we desire at any time. I’ve chosen to display the results as XML for simplicity’s sake. I could even format the execution results as JSON using the DataContractJsonSerializer and pass that data into a jQuery-driven data table implementation for a more familiar grid-like view, not to mention a much more user-friendly interface to work with.
I’ve got numerous plans for features I’d like to implement for this tool. I will consider releasing some of the framework and tool code if I can lighten up some of the dependencies involved.
As usual, when I blog, I only blog about things I find that are unique and that haven’t been posted before. Today is no exception. I give you an HTML formatter for T-SQL, written in C# using Regular Expressions.
public static string HTMLColorizeSQL(string sql)
{
string output = HttpUtility.HtmlEncode(sql);
output = Regex.Replace(output,
@"^--(?<comment>[^\r\n]*)(?<post>\r\n|$)",
@"<span class=""sql_comment"">--${comment}</span>${post}",
RegexOptions.IgnoreCase | RegexOptions.Multiline
);
output = Regex.Replace(output,
@"(?<=(\[|\b))(?<keyword>(SELECT|FROM|WHERE|ORDER|INNER|JOIN|OUTER|LEFT|RIGHT|CROSS" +
@"|DISTINCT|DECLARE|SET|EXEC|NOT|IN|IS|NULL|BETWEEN|GROUP|BY|ASC|DESC|OVER|AS|ON" +
@"|AND|OR|TOP|GO|CASE|WHEN|ELSE|THEN|IF|BEGIN|END|LIKE))\b",
@"<span class=""sql_keyword"">${keyword}</span>",
RegexOptions.IgnoreCase
);
output = Regex.Replace(output,
@"(\b(?<keyword>ROW_NUMBER|COUNT|CONVERT|COALESCE|CAST)(?<post>\())",
@"<span class=""sql_function"">${keyword}</span>${post}",
RegexOptions.IgnoreCase
);
output = Regex.Replace(output,
@"(?<param>\@[\w\d_]+)",
@"<span class=""sql_param"">${param}</span>",
RegexOptions.IgnoreCase
);
return output;
}
Please allow me to express how much I HATE the use of regular expressions for parsing tasks like this. Normally I would be completely content to sit down and hack up a custom parser in C# for T-SQL or at least try to generate one from existing tools. I figured the most I’m trying to accomplish here is syntax highlighting, so what’s the harm in going with Regex here?
Note that this implementation comes with a few caveats.
The CSS that I am using is in this form:
/* SQL keyword: a span with a 'sql_keyword' class not found within an that has a 'sql_comment' class */
:not(.sql_comment)>span.sql_keyword
{
color: #33f;
font-weight: bold;
}
/* SQL function: a span with a 'sql_function' class not found within an that has a 'sql_comment' class */
:not(.sql_comment)>span.sql_function
{
color: #3f6;
font-weight: bold;
}
/* SQL parameter */
:not(.sql_comment)>span.sql_param
{
color: #993;
font-weight: bold;
}
/* SQL single-line comment */
.sql_comment
{
color: Olive;
font-weight: bold;
}
The key pattern to take away here is the use of the :not(x) CSS selector. It says to format a keyword, parameter, or function name if and only if the span is not contained within a span with the class ’sql_comment’ applied.
I hope you enjoy that and I hope to see future improvements coming back this way!
Have you ever found it a pain to try to debug the SQL query generated by LINQ-to-SQL? For my employer, Kaplan, I’ve designed a SQL query auditing “framework” that allows us to audit all of the LINQ generated SQL queries from our data repository implementation class. (I use the term “framework” here lightly because it is no more than a few “shim” methods implemented in an abstract base class that the repository implementation class derives from.)
Let’s take the following code snippet:

This is an actual method implementation we use in our system and it conforms to a set of guidelines necessary to enable this auditing support. The main concept that should stick out here is that we don’t just return the `query` nor do we enumerate it here. We instead call this funny-looking AuditEnumerable method, which is part of our SQL auditing framework.
IEnumerable<U> AuditEnumerable<T, U>(IQueryable<T> query, Func<T, U> map)
The whole point of this method is to gain access to the IQueryable before anyone gets a chance to enumerate over it. Once you begin enumeration on an IQueryable (e.g. with a foreach or a .ToList()), you’ve told LINQ-to-SQL that you wish to translate that IQueryable instance into a SQL query and execute it against the database and then enumerate over the results of that SQL query.
This AuditEnumerable method “interrupts” that process and only translates the LINQ IQueryable structure into a SQL query and then stops there. When auditing mode is enabled, it returns an Enumerable.Empty<U>().
The purpose of this auditing framework is to switch OFF data access and only trace out what actual query would be executed against the database. This auditing framework produces invaluable information for both developers and DBAs.
Now, we can construct some simple user interface for capturing and browsing this auditing information per each repository method. I’ve done just that with a very crude but effective Visual Studio unit test class. Yes, it is an abuse of the unit test framework, but it is so darn handy and productive I really have no intention of removing it. I’ll most likely move it into a hosted ASP.NET page that generates these reports on-the-fly; it will probably sit next to our WCF endpoints’ SVC files on the web service host. That would make it easily accessible to DBAs, since they’re probably not too keen on cracking open Visual Studio just to do SQL code reviews.
Below is a sample output from this unit test. The unit test class is code-generated to enable the auditing mode of the data repository class and to call each data repository method that declares itself to only read data. (We have a method naming convention whereby a method that begins with “Get” must do no data writes. The code generator discovers these methods and generates auditing boilerplate code to get the SQL query text out.)

Here is an example of the unit test class which produces this sort of output (trimmed for brevity / screenshot purposes):

NOTE: I do not normally condone this indentation pattern. This is purely for display purposes only.
Basically, we’ll have a bunch of [TestMethod] decorated methods, one for each “Get” method defined on our ICoreRepository interface. Before each test method is run, a new StringWriter is created to write to a StringBuilder and that is passed to the BeginSQLAuditing method defined on the CoreDataRepository implementation class (technically it is on the abstract base class this is derived from). This tells the auditing code where to output the query text and parameter information to. Once the test method has completed, the clean-up method calls EndSQLAuditing() which gets back the StringWriter instance we originally passed in and Flush()es that. Now we can call .ToString() on the original StringBuilder that now contains the auditing information and write that to Console.Out! This shows up in the “Standard Console Output” section of the unit test results as seen above.
There is so much going on behind the scenes and lots more to discuss about the auditing framework that I would love to go into, but I think this post is long enough as it is now. I may consider writing Part 2 but don’t hold your breath.
What’s on your resume? Is it just a collection of what I refer to as buzzword bingo with filler words in between? How does it stack up against other resumes?
Oh, you listed C# 3.0 on your resume? Great! Just what we’re looking for. You have experience with ASP.NET? Wow! What a match! Let me put your resume next to all the other identical copies in my big whoop folder.
When I take a look at a resume I expect to see at least one thing that tells me what you are capable of. One thing that shows what you can do better than others. No, I don’t care if you have experience with the MOSS framework or that you’ve used Ektron CMS. Show me what tasks you’ve done to better the quality of the software you were involved with.
Things that are particularly impressive to me are experience with multi-threaded programming, diagnostic abilities, and having an valid opinion about some piece of technology. Of those, I would have to say that diagnostic abilities reign supreme. Having good diagnostic skills lets you solve just about any problem that comes across your plate. Find a clever way to describe such abilities on your resume.
I could not care less the architecture or purpose of your previous projects unless you were primarily or secondarily responsible for designing such an architecture. Why bother wasting precious white space on such useless information that tells me nothing about you? I’m not interested in acquiring your previous projects. I might be more interested to see what you can do for me or my company.
Don’t worry about proper resume formatting or whatever your English courses have engrained in your brain. Nobody gives a rip about the layout of your resume. Focus on content, not form. One page, maybe two pages max. If you feel the need to stretch it out beyond that, only dedicate that space to providing valuable information as to what you have done yourself, not your prior teams.
Furthermore, don’t pigeonhole yourself into breaking up your resume into the de facto standard sections: objective, skills, experience, awards, etc. Just find some organized way to convey the information we as employers (or interviewers) need to see to set you apart. The more unique your resume looks, the better shot you have at grabbing my attention.
Remember, your resume is your advertising material. It should serve a purpose other than the circuitousness of simply being a resume. You are on the market. You are selling your skills, knowledge, wisdom, and experience. Mark down some highlights which show you off. Nobody rewards points for modesty on a resume.
Having had enough of the tired old “ask a question get an answer” interview tactics, I decided to put together a test bed application to test the interviewee’s real-world problem solving skills. Based on feedback from other team members, I did not actually force this upon on any of our recent interviewees.
The purpose of the test is to find out if the interviewee can actually develop an algorithm to solve a problem from scratch and can fit it into an existing project. Another critical skill to test is how well the candidate can read specifications and more importantly how attentive to detail he/she is.
This test is based on an algorithm I developed long long ago to convert game maps from Wolfenstein 3-D to DooM 2(which was quite a success but I unfortunately have lost the code since then). The two games are based on very different technologies and the ways in which each stores map information is completely different. Wolf3D stores its maps as a simple 2D square tiled grid filled with block type numbers where the number represents a specific wall texture type and sometimes an implied function like a door. DooM (and DooM 2) store their maps as a set of convex polygonal sectors with a floor and ceiling height. A sector is made up of a set of line segments with special properties applied to one or both sides of the line segment.
The algorithm that the candidate is tasked to implement must convert the incoming 2D tiled grid filled with solid/empty values into a set of line segments which represent the inner edges of the walls found between a solid and an empty tile. I chose to simplify the requirements to deal only with solid/empty tiles instead of 100-or-so different tile types.
Here is the algorithm’s method signature:
IEnumerable<LineSegment> TransformBlocksToLineSegments(RectangularMap map, Point startingPosition)
There are many ways to implement the algorithm and many detail points to consider:
There are 6 sample solutions implementing the algorithm using various combinations of these points to compare the candidate’s implementation against. The test bed application also includes a benchmark feature which compares the averaged run times of each implementation.
The intent of the test is a take-home problem where the candidate can spend as much or as little time as he/she likes. The 6 sample implementations are included in a binary-only assembly form, but this is easy to defeat with a tool like Reflector.
The fun part is the ability to draw out rectangles on the grids and to see the live results of the selected algorithm and how it reacts to the new information in the map. Left-click-dragging will create an empty rectangular space and right-click-dragging will create a solid rectangular space.
If you are planning to use this test, be aware of cheating. Have the candidate explain their implementation to you and be sure they’re not just copying someone else’s solution and taking credit for the work.
Download here:
I cannot stress enough the importance of knowing how LINQ queries work when they are based on an IEnumerable source.
When one defines a query based on an IEnumerable source, the query variable represents just that: the query, NOT the results of enumerating the query.
Each time you enumerate over the query object, you are calculating the results of that query on-demand. There is no caching of results. The LINQ IEnumerable implementation makes no assumptions that enumerating the same query twice in a row will produce the same results and so it let’s you do so without any qualms.
If what you meant to do was to run the query once and store the results for future operations to work on, then creating a List
var query = from x in something select x;
var results = query.ToList();
Use the `results` variable when you want to reference the results of `query`.
The same restrictions apply to IQueryable LINQ queries. When enumerating over an IQueryable, it calls the underlying IQueryProvider to transform your query operations into whatever form is best for that provider to execute your query against its data source.
Be *very* careful when including IQueryable variables in another IQueryable LINQ query because you will be effectively telling your query provider to combine those queries together, and it will be up to the query provider to figure out how to do so or to raise an exception telling you that that’s unsupported or simply not possible. If you rather meant to pass the results of that query into another then you should use the AsEnumerable extension method. That should guarantee that the two queries are kept independent and that the results of the first are fed into the second.
As an aside, the ToList extension method *always* creates a new List
Also, when taking an IEnumerable
Tags: c#, ienumerable, linq
After redesigning our data, business, and services layers to be interface driven, I wanted to keep the amount of boilerplate code written by developers down to an absolute minimum. The best way I know how to do this is through code generation.
T4 templates are a good solution to this problem. T4 might not be as well known as other popular code generation tools but the fact that you get it for free and it’s integrated into Visual Studio is a very strong selling point in my opinion. The less impact it has on your existing development environment requirements, the better.
When you start thinking about generating code based on compiled code in an assembly, the term “reflection” should spring to mind. If it doesn’t, this article isn’t for you.
If you have had previous experience with .NET’s built-in reflection API you might be aware of the small snag whereby assemblies loaded for reflection are locked for exclusive access and cannot be unloaded until the AppDomain which loaded them is torn down.
For T4 templates this poses a somewhat significant problem. What problem is this? The T4 template generator invoked by Visual Studio is run in its own AppDomain and that AppDomain instance is kept around and recycled once every 25 uses. If you were to use reflection in your T4 template and load up your assembly, you would not be able to recompile that assembly until the 25th run of the T4 template tool. Yuck.
You might be saying at this point, “well now wait a minute… you can create a temporary AppDomain for reflection, do your reflection work in there, and tear down the temporary AppDomain to solve that problem!” … and you may be right. As for me, I’ve attempted that solution myself to no avail and was frought with nasty restrictions here and there. In theory it should be quite simple. In practice it is quite the daunting nightmare. Trust me, you don’t want to go there. Pain and suffering awaits you on that dark path. Be warned.
So, now that reflection is out, what’s left? After much googling of the issue I discovered the Microsoft.Cci.dll introspection API used by FxCop.
This assembly exposes a managed code library that is able to read .NET type metadata from an assembly file without actually loading the assembly into an AppDomain prepared for execution. It does this by opening the file as a binary stream, parsing out the metadata information in the stream and keeping it in memory, and closing the file. No nasty file locks are held on the assembly file. This suits our requirements for the T4 templating system quite nicely and is in fact very speedy, or rather speedy enough for code generation tasks.
A significant down-side to using this 3rd party API is that it is not reflection, and it has its own set of types for representing metadata. It does, however, look similar in many ways to reflection. There is no documentation that I’m aware of, but using a free copy of .NET Reflector from RedGate on the Microsoft.Cci.dll assembly itself should get you enough information on how to use the API.
Another pain point in using T4 templates is that there is no intellisense support in Visual Studio for editing them, so it’s back to old-school days of writing code in a dumb text editor, praying it will compile, and execute properly. There’s also not a great story around debugging code in the T4 templates either. I’ve managed to hobble along in debugging my own templates, but it would be a maintenance nightmare if you were to have multiple developers working on these templates.
Next post I might share with you some of my generic Microsoft.Cci.dll common utility methods and some example code.
To find Microsoft.Cci.dll you’ll need a copy of the latest FxCop tool. Ill have to check the version number I downloaded but I do remember that an older version of the dll included some nastiness that breaks C# 3.0 usage of the ‘var’ keyword. That compiler error will surely throw you for a loop if you’re not prepared. Not to fear, however, the latest version fixes this problem.
Tags: code generation, fxcop, reflection, t4
Most of the time when asked to give technical interviews, I do a quick search to find some good thought-provoking and information-providing interview questions. Every single time I’ve come up with some of the most appalling lists of questions that are based on regurgitation ability or that are too insanely technical or trying-to-be-too-clever-and-tricky to be useful to the interviewer at all.
Now, I am not one to shy away from technical details by any means. In fact, I think our communication styles built up from “Corporate America” have guided us away from being comfortable with discussing any topic in any amount of depth. Most of the time, details need to be “taken offline,” whatever that means… but that is a discussion topic for another post.
My point is that interview questions should focus on the candidate’s problem-solving ability and not the precise knowledge of the C# 3.0 language specification, the CLR 2.0 specification, or deep knowledge of the implementation details of the ASP.NET stack. Unless, of course, you are in the process of hiring a developer which must have considerable experience in a specific domain of expertise.
Offer your candidate a set of very primitive “hey can we first determine you are in the right market” style questions relating to basics of development. Based on answers given, try to magnify the area related to the question with a more in-depth focused question. Iterate until the candidate can no longer keep up on that train of thought and then move onto the next subject area.
Diagnostic skills (i.e. the ability to debug a program) is a critical skill in this market. Tailor your questions to specific real-world problems you have had experience diagnosing yourself. Get the candidate talking in the terminology of the field to see if they know what they say they know. Try to evaluate where their diagnostic abilities lie according to the depth of thought evident (or not) in their answers.
When interviewing, ask yourself if you’d rather hire/work with a specialized-skill team member (e.g. the guy that knows everything about AS/400s or SQL or C#) or an overall “smart guy” able to solve real problems and to learn from experience and apply diagnostic abilities and logic. Focus your questions to the candidate according to how you answered this question.
I will soon be preparing a hierarchy of good technical interview questions since I need it for my own interviews. Also, since I haven’t found a list of questions on the Internet already, it certainly wouldn’t hurt to put one up if not only for my own future reference. Hopefully at least one other person may find it useful.
I would like to share with you a Visual Studio T4 template I use to generate strongly-typed identifiers for my domain models. These strongly-typed identifiers are glorified `int` wrappers. When designing your domain models you should choose to store references as strongly-typed identifiers because it exposes yet another layer of abstraction. Your domain models should never have to know if they reference one another with `int`, `long`, `string`, `Guid`, or any of the other myriad of identifier types commonly used. They should only be concerned with whether the identifiers represent are equal values.
Having a centralized and well-named type to represent an identifier provides many other benefits than just abstraction and separation of concerns. It gives you the ability to have the compiler do some enforcement on your implementation code. I’m sure you’ve run into a few bugs where you’re dealing with model identifiers close in name where you might be confused and accidentally copy/paste code expecting one range of identifiers into a new method that should have expected a different range of identifiers. These two distinct identifier ranges are both represented as `int`s in your code and your compiler would never tell you since the error is a semantic one, not a syntactic one. Creating strongly-typed wrappers for these different identifier ranges now makes the problem a syntactic one that your compiler can check for you. Furthermore, you get benefits of method overloading whereas you couldn’t before when using the primitive types like `int`.
An example from a system I’m working on is as follows:
interface IStaffRepository
{
Staff GetStaff(StaffID id);
Staff GetStaff(TeacherID id);
}
This code allows me to use two distinct identifier types to overload a single method in an interface that is supposed to retrieve general staff information. A specific type of staff member is a teacher which has a reference back to a Staff record via StaffID. I can choose to either get the staff information given a `StaffID` or a `TeacherID`, two identifier types which represent identity key values of two distinct SQL tables. If I had gone with a more conventional approach and used `int`, this overload could not have been possible. Of course I would have just foregone the overload and declared two separately named methods, GetStaff(int staffID) and GetStaffByTeacherID(int teacherID). This is all a matter of cosmetic preference, but I believe it gives the design a bit more of an elegant feel and allows for more expressiveness in the interface design.
In case you’re wondering, there are implicit conversion operators to and from `int` defined on the template. This makes it easy to construct a strongly typed identifier from an integer constant for testing purposes or perhaps to create one from external data sources where the identifier is represented as an `int`. For example, ASP.NET MVC allows one to define public action methods with virtually any set of typed parameters and it will attempt to convert HTTP form and query-string values from their `string` representation into the types exposed by the method’s parameters.
public class MyController : Controller
{
public ActionResult GetStaff(int id)
{
// Convert the `int` id parameter from the route into a `StaffID` using the
// implicit int conversion operator defined on `StaffID` struct:
StaffID sfid = (StaffID)id;
// Example code to instantiate a default implementation of our
// earlier-defined `IStaffRepository` interface:
IStaffRepository repo = new StaffRepositoryDefaultImpl();
Staff staff = repo.GetStaff(sfid);
// We intend to display a view named "GetStaff" providing a `Staff` view model type:
return View((object)staff);
}
}
The template can and should be extended to allow customization of base identifier type that the strongly-typed identifier wraps rather than just assuming `int` for all. As it is, all my models come from a data schema which uses `int` for identity values so it’s fine with me.
<#@ template language="C#v3.5" debug="True" hostspecific="True" #>
<#@ output extension=".generated.cs" #>
<#
// This .tt file is a T4 template. T4 is a code-generation template language implemented by
// Visual Studio and used for simplistic code-generation scenarios like this.
// The pattern implemented here is to give each model identifier a strongly typed container for
// its underlying primitive type value. This way, methods can be overloaded based on identifier type
// and bugs involving the wrong identifier used with a method call can hopefully be reduced.
// Unfortunately, there's no better way to define each of these identifier structs other
// than code-generating them. A base class, or any other means of code sharing, would not
// help since it would defeat the purpose of keeping the identifiers orthogonal and hence
// non-convertible to each other.
// Add new identifier names here to be auto-generated using the same boilerplate code:
// The columns are "ClassName", "BasePrimitiveType", "XMLSummary".
var idNames = new[] {
new string[3] { "AbcModelID", "int", "A unique identifer for a Abc model" },
new string[3] { "XyzModelID", "int", "A unique identifier for a Xyz model" },
new string[3] { "EventInstanceID", "Guid", "A unique identifier for a unique instance of an event" },
// add more identifier definitions here...
};
#>
// WARNING: This code is auto-generated by Identifiers.tt T4 template. Any modifications made to
// this file will be rendered ineffective as it will be code-generated at build time anyway.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Your.Namespace.Here
{
<#
for (int i = 0; i < idNames.Length; ++i)
{
string idName = idNames[i][0];
string idType = idNames[i][1];
string comment = idNames[i][2];
#>
#region <#= idName #>
///
/// <#= comment #>
///
///
/// This type is explicitly convertible to int and vice versa using the (int) cast operator.
/// For example, <#= idName #> id = (<#= idName #>)10; int value = (int)id;
///
[Serializable]
public struct <#= idName #> : IEquatable<<#= idName #>>
{
<#= idType #> _value;
public <#= idName #>(<#= idType #> value) { this._value = value; }
public static explicit operator <#= idType #>(<#= idName #> id) { return id._value; }
public static explicit operator <#= idName #>(<#= idType #> value) { return new <#= idName #>(value); }
public static bool operator ==(<#= idName #> a, <#= idName #> b) { return a._value == b._value; }
public static bool operator !=(<#= idName #> a, <#= idName #> b) { return a._value != b._value; }
public override string ToString() { return _value.ToString(); }
public override int GetHashCode() { return _value.GetHashCode(); }
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj.GetType() != typeof(<#= idName #>)) return false;
return this.Equals((<#= idName #>)obj);
}
public bool Equals(<#= idName #> other) { return _value.Equals(other._value); }
}
#endregion
<#
if (i < idNames.Length - 1) WriteLine(String.Empty);
}
#>
}