Рефлексия, кодогенерация и обёртка - C#

Узнай цену своей работы

Формулировка задачи:

Доброго времени суток! Сначала прикладная задача: имеется статический класс, для которого необходимо делать не статическую обёртку. Руками сделать эту обёртку не приятно, но можно. Но проект живой, развивающийся и статический класс тоже, т.е. в нём время от времени появляются новые члены. А это значит что обёртку нужно постоянно актуализировать, что совсем уж ни в какие ворота. Я долго думал что с этим делать, рассматривал различные варианты и остановился на следующем: Custom Tool + кодогенерация. Мне кажется это будет идеальным решением. В конечном счёте обёртка всегда актуальная и для этого ничего не надо делать. Если я не прав и есть варианты по лучше, самое время мне сообщить об этом. Едем дальше. Нагуглил я статей про Custom Tool и примерно представляю как это работает, может быть по ходу ещё возникнут какие-то вопросы, но давайте пока считать этот вопрос решённым. Сейчас же у меня есть вопросы по реализации собственно кодогенератора. И так, опуская детали, Custom Tool принимает на вход файл, на основе которого мы будем генерить свой файл, обёртку для класса в моём случае. И тут я вижу два пути, простой и правильный. Простой. Добавляем в кодогенератор референс на мою сборку с оборачиваемым классом, игнорируем входной файл и просто генерим то что нам нужно через рефлексию. Но хочется сделать по правильному, а по правильному, это не завязываться на конкретную реализацию и сделать универсальный кодогенератор, который можно будет использовать и в будущем для других проектов. А это значит никаких референсов на проект и работать со входным файлом. Отсюда у меня вытекают 2 вопроса: 1. Можно ли как-то заюзать рефлексию имея лишь текстовый файл с классом? 2. Может быть есть какой-то удобный способ парсить cs файл? Мои навыки гугления не помогли, а парсить файл руками совсем не хочется. У простого способа есть ещё один недостаток, Custom Tool срабатывает когда изменяется файл к которому он привязан. А рефлексия подозреваю не увидит изменений в классе, пока он не будет скомпилирован. Мелочь, а не приятно.

Решение задачи: «Рефлексия, кодогенерация и обёртка»

textual
Листинг программы
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE"  #>   

namespace Wrappers
{
<#  
string projectName = "t4generatewrapper";
string[] classNames = {"t4generatewrapper.ClassToWrap"}; 
IServiceProvider serviceProvider = (IServiceProvider) this.Host;  
EnvDTE.DTE dte = (EnvDTE.DTE) serviceProvider.GetService(typeof(EnvDTE.DTE));  
Project currentProject = null;
foreach (Project p in dte.Solution.Projects)
{
	if(p.Name == projectName)currentProject = p;
}

foreach (string classFullName in classNames)
{
	var classCode = currentProject.CodeModel.CodeTypeFromFullName(classFullName);
#>

public class <#= classFullName.Split('.').Last() #>Wrapper
{

<# foreach (CodeFunction cf in  classCode.Members.OfType<CodeFunction>())
	{
	
	var pars = string.Join(", ", from CodeParameter p in cf.Parameters select p.Type.AsFullName + " " + p.Name);
	var args = string.Join(", ", from CodeParameter p in cf.Parameters select  p.Name);
	if(cf.Type.AsFullName == "System.Void")
	{#>
	public void <#= cf.Name #> (<#= pars #>)
	{
		<#= classFullName + "." + cf.Name #>(<#= args #>);
	}
			<# } 
			else{ #>

	public <#= cf.Type.AsFullName #> <#= cf.Name #>(<#= pars #>)
	{
		return <#= classFullName + "." + cf.Name #>(<#= args #>);
	}
<#} 
} #>
 }
<# 
} #>
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4 из 5
Похожие ответы