C# – Generating C# Classes from Existing C# Class

ccode generationtemplates

I have simple POCO classes, like this:

public class Book
{
    public string BookId { get; set; }
    public string Name { get; set; }
    //etc...
}

I want to get all those classes and generate another classes, which called viewmodels, for example, the output would be:

public class BookViewModel
{
    [HiddenInput(DisplayValue = false)]
    public string BookId { get; set; }

    [Required]
    public string Name { get; set; }
    //etc...
}

This is the simplest example, in real life I would also want to generate special classes, which implements database operations logic with corresponding entities.

However, how should I do this? I'm using ASP.NET Core right now, but if solution doesn't exist in Net Core, I'll just use it where it exists and copy-paste result.

So, I want generate C# classes from other classes, how should I do this?

Best Answer

If that's all you have and it isn't practical / feasible for you to have a common single source of truth to generate your different artifacts, you may find the T4 template feature helpful.

For example, let's assume that "Dummy" is the class library project of your model in the same solution, with, say, in Dummy.cs:

namespace Dummy
{
    public class Something
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }

    public class SomethingElse
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }
}

Then, in your view model class library, you can use Visual Studio's

"Add > New Item... > Visual C# Items > Text Template"

to add, in a "ViewModel.tt":

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(SolutionDir)\Dummy\bin\Debug\Dummy.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="Dummy" #>
<#
  // choose a convenient "anchor type" from your model, e.g., a base class or enum type, etc
  var model = typeof(Dummy.Something).Assembly.GetTypes();
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DummyViewModels
{
<# foreach (var type in model) { #>
    public class <#= type.Name #>ViewModel
    {
<# foreach (var property in type.GetProperties()) { #>
        public <#= property.PropertyType.Name #> <#= property.Name #> { get; set; }
<# } #>
    }
<# } #>
}

which should yield, after "right-click > Run Custom Tool" on the "ViewModel.tt" (in the same project), the following "ViewModel.cs":

namespace DummyViewModels
{
    public class SomethingViewModel
    {
            public Int32 Id { get; set; }
            public String Name { get; set; }
    }

    public class SomethingElseViewModel
    {
            public Int32 Id { get; set; }
            public String Name { get; set; }
    }
}

'Hope this helps.