Got an idea that's been in my head for a while, and I'm at the point where it would benefit my current project if I could find a way to implement it.
I'm building out an API that has a ton of CRUD functionality, specifically a lot of Add/Edit stuff that is, for all intents and purposes, doing the same operations but just with or without an ID to indicate an existing record.
For example, here is what gets posted to the API to add a new address:
public class AddressDto
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string Postcode { get; set; }
//...
}
And here is what gets posted to the API to update an existing address:
public class ExistingAddressDto
{
public Guid Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string Postcode { get; set; }
//...
}
As you can see, basically the same thing, just with an extra Id
field. This obviously isn't an issue when just considering these two classes, but it's becoming clearer as the codebase grows that we're going to have a huge number of duplicate DTO's for very little benefit. We've experimented with inheriting a base class that adds just the Id
field, but even this leads to declaring extra classes.
I wondered if it would be possible to build out a generic type that could be wrapped around another class, and add an Id
property onto whatever was passed to it as the template. Something like this:
//declaration
public class Existing<T> where T : class
{
public Guid Id { get; set; }
public T Value { get; set; } //ideally would love to not have this as a nested property
}
//in use
var existingAddress = new Existing<AddressDto>();
I feel like the idea can work in theory, but what I'm trying to see is if it's possible to have Id
on the same level as properties of the templated object. At present, you would access the properties like this:
var id = existingAddress.Id;
var city = existing.Value.City;
I think what I'm looking for is something like being able to use JavaScript's "spread" operator, or some equivalent, but not sure if this part is possible or how to implement it.
Any advice on this would be great, thanks!
The way I'd approach these kinds of problems is with source generation. Specifically for your case, I'd parse all classes that end with Dto
(and don't start with Existing
) and create a class for each called Existing<name>Dto
with the same fields and an additional Id
field as you describe.
This way you get no inheritance, no nested fields and no reflection, just plain code that's kept up to date by your compiler.