Есть ли сериализатор для .net, который выведет код С#?
Я ищу сериализатор, который мог бы взять экземпляр, и сериализовать его на строку, которая будет содержать код С#, представляющий содержимое графика.
Класс будет функционировать аналогично SerializeObject
в JSON.NET.
Я знаю, что будет работать только очень узкий набор структур, но те, которые мне интересны, довольно просты, и они будут.
Бонусные баллы, если кто-нибудь знает Visualizer Visualizer с аналогичной функциональностью.
Edit:
Выход будет использоваться в другом приложении во время компиляции. Мне не нужно десериализовать вывод (код С#) во время выполнения, он сохраняется в файле для анализа.
var foo = new Foo() { Number = 1, Bar = new Bar() { Str = "Bar"}};
string sourceCode = Magic.SerializeObject(foo);
Вывод:
Foo obj = new Foo();
obj.Number = 1;
obj.RefType = null; // infer this
obj.Bar = new Bar();
obj.Bar.Str = "Bar";
Ответы
Ответ 1
да, и нет...
Ближайшее решение называется CodeDOM, это то, что большинство дизайнеров и мастеров Visual Studio используют для генерации кода.
После более подробного рассмотрения ваших комментариев, я думаю, вы должны внимательно прочитать раздел
Ответ 2
Написание чего-то подобного на самом деле относительно просто с помощью CodeDom:
class CSharpSerializer
{
private readonly Dictionary<string, int> m_locals =
new Dictionary<string, int>();
private readonly List<CodeStatement> m_statements =
new List<CodeStatement>();
private string GetVariableName(string suggestedName)
{
suggestedName = suggestedName.TrimEnd("0123456789".ToCharArray());
int n;
if (m_locals.TryGetValue(suggestedName, out n))
{
n++;
m_locals[suggestedName] = n;
return suggestedName + n;
}
m_locals[suggestedName] = 1;
return suggestedName;
}
public string SerializeObject(object obj)
{
m_statements.Clear();
// dynamic used to make the code simpler
GetExpression((dynamic)obj);
var compiler = new CSharpCodeProvider();
var writer = new StringWriter();
foreach (var statement in m_statements)
{
compiler.GenerateCodeFromStatement(
statement, writer, new CodeGeneratorOptions());
}
return writer.ToString();
}
private static CodeExpression GetExpression(int i)
{
return new CodePrimitiveExpression(i);
}
private static CodeExpression GetExpression(string s)
{
return new CodePrimitiveExpression(s);
}
private static CodeExpression GetExpression(DateTime dateTime)
{
// TODO: handle culture and milliseconds
return new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(typeof(Convert)), "ToDateTime",
new CodePrimitiveExpression(Convert.ToString(dateTime)));
}
// and so on for other primitive types
// and types that require special handling (including arrays)
private CodeExpression GetExpression(object obj)
{
if (obj == null)
return new CodePrimitiveExpression(null);
var type = obj.GetType();
string typeName = type.Name;
string variable = GetVariableName(
typeName[0].ToString().ToLower() + typeName.Substring(1));
m_statements.Add(
new CodeVariableDeclarationStatement(
typeName, variable, new CodeObjectCreateExpression(typeName)));
foreach (var property in type.GetProperties(
BindingFlags.Public | BindingFlags.Instance))
{
var expression = GetExpression((dynamic)property.GetValue(obj));
m_statements.Add(
new CodeAssignStatement(
new CodePropertyReferenceExpression(
new CodeVariableReferenceExpression(variable),
property.Name),
expression));
}
return new CodeVariableReferenceExpression(variable);
}
}
Существует много случаев, когда этот код не сработает, но для корректных типов (публичный конструктор по умолчанию, все свойства публичного экземпляра имеют сеттеры, не имеет никакого важного состояния, скрытого в полях или непубличных свойствах, без циклических ссылок, без конфликтов пространства имен и т.д.), он будет работать.