Skip to content

Instantly share code, notes, and snippets.

Created August 4, 2014 11:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/77525ccd19c422b4a51e to your computer and use it in GitHub Desktop.
Save anonymous/77525ccd19c422b4a51e to your computer and use it in GitHub Desktop.
Wrap Type And Copy To Clipboard
Use case:
Need to wrap that RSS/whatever data class for some quick and dirty use of eg. teafiles or stsdb4?
I have the code below in my personal library that's always referenced, so I just temporarily add this line into whatever project I'm working. Ideally I could just right click a type and select a custom option to have the code below run but I'll leave that to someone who knows more about extending VS than I do.
CodeDom.WrapTypeAndCopyToClipboard(typeof(System.ServiceModel.Syndication.SyndicationItem), System.CodeDom.MemberAttributes.Public)
Run that line and the specified type, such as SyndicationItem for RSS/Atom feeds, ends up in your clipboard like this, after which all you need to do is do some minor editing (mod the complex types and constructor logic with whatever required by your serializer):
// The commented lines are SyndicationItem's fields, rest are properties
public class SyndicationItemWrap
{
public Uri BaseUri;
public SyndicationContent Content;
public TextSyndicationContent Copyright;
public string Id;
public DateTimeOffset LastUpdatedTime;
public DateTimeOffset PublishDate;
public SyndicationFeed SourceFeed;
public TextSyndicationContent Summary;
public TextSyndicationContent Title;
// public ExtensibleSyndicationObject Extensions;
public SyndicationItemWrap()
{
}
public SyndicationItemWrap(SyndicationItem s)
{
BaseUri = s.BaseUri;
Content = s.Content;
Copyright = s.Copyright;
Id = s.Id;
LastUpdatedTime = s.LastUpdatedTime;
PublishDate = s.PublishDate;
SourceFeed = s.SourceFeed;
Summary = s.Summary;
Title = s.Title;
// Extensions = s.extensions;
}
}
//.NET 4.5, reference Windows.Forms or PresentationCore for clipboard
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
public class Clipboard
{ //clipboard manipulation requires thread to be STA-apartment thread, beats me why BCL doesn't do this for you
public static void SetText(string s)
{
PrepareAndExecuteSTA(() => { System.Windows.Forms.Clipboard.SetText(s); } );
}
public static void PrepareAndExecuteSTA(Action act)
{
if (System.Threading.Thread.CurrentThread.GetApartmentState() != System.Threading.ApartmentState.STA)
{
var thread = new System.Threading.Thread(() => { act(); });
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
thread.Join();
}
else act();
}
}
public class CodeDom
{ // some string stuff missing from BCL
public static string Repeat(this string input, int count)
{
if (!string.IsNullOrEmpty(input))
{
StringBuilder builder = new StringBuilder(input.Length * count);
for (int i = 0; i < count; i++) builder.Append(input);
return builder.ToString();
}
return string.Empty;
}
public static string FirstCharToLower(string str)
{
if (String.IsNullOrEmpty(str) || Char.IsLower(str, 0))
return str;
return Char.ToLowerInvariant(str[0]).ToString() + str.Substring(1);
}
public static string FirstCharToUpper(string str)
{
if (String.IsNullOrEmpty(str) || Char.IsUpper(str, 0))
return str;
return Char.ToUpperInvariant(str[0]).ToString() + str.Substring(1);
}
///////////////////////////////////////// CodeDom and reflection code mixed. the c# text generation is done in memory
public enum Case
{
AccessibilityBased,Preserve, Upper, Lower
}
public static string WrapTypeAndCopyToClipboard(Type t, MemberAttributes attributes = MemberAttributes.Public, Case firstLetter = Case.AccessibilityBased)
{
var c = GenerateCSharpCode(t, attributes, firstLetter);
var cs = TransformToCS(c);
Clipboard.SetText(cs);
return cs;
}
public static string TransformToCS(CodeCompileUnit ccu)
{
CompilerParameters cp = new CompilerParameters();
CompilerResults cr;
var sb = new StringBuilder();
CSharpCodeProvider csharpcodeprovider = new CSharpCodeProvider();
var indent = " ";
using (var ms = new MemoryStream())
using (var tw1 = new IndentedTextWriter(new StreamWriter(ms), indent))
{
csharpcodeprovider.GenerateCodeFromCompileUnit(ccu, tw1, new CodeGeneratorOptions());
//cp.GenerateExecutable = false;
//cp.OutputAssembly = "CSharpSample.exe";
//cp.GenerateInMemory = true;
//cr = csharpcodeprovider.CompileAssemblyFromDom(cp, ccu);
tw1.Flush();
ms.Position = 0;
int ind = 0;
using (var sr = new StreamReader(ms))
{
string l=null;
while ((l=sr.ReadLine()) != null) {
//l = l.Trim();
if (string.IsNullOrWhiteSpace(l) || l.StartsWith("/")) continue;
bool a = false;
if (l.EndsWith("{")) { l = l.TrimEnd('{'); a = true; }
sb.Append(l.Replace(" @"," "));
if (l.EndsWith(";")) sb.AppendLine();
if (l.EndsWith("}")) { sb.AppendLine(); ind--; }
if (a) {
sb.AppendLine(); sb.AppendLine(indent.Repeat(ind) + "{"); ind++;
}
}
}
}
return sb.ToString();
}
public static CodeCompileUnit GenerateCSharpCode(Type t, MemberAttributes attributes, Case firstLetter)
{
CodeCompileUnit compileUnit = new CodeCompileUnit();
// namespace CodeDomSampleNS { // "" = nothing
CodeNamespace ns = new CodeNamespace("");
// Create using statement - "using System;"
CodeNamespaceImport firstimport = new CodeNamespaceImport("System");
// using System;
//codedomsamplenamespace.Imports.Add(firstimport);
AddClass(ns,t,attributes,firstLetter);
compileUnit.Namespaces.Add(ns);
//// code generation options
//CodeGeneratorOptions opt = new CodeGeneratorOptions();
//opt.BracingStyle = "C";
//opt.BlankLinesBetweenMembers = false;
//opt.VerbatimOrder = false;
//// generate the code and return it
//provider.GenerateCodeFromNamespace(myNamespace, tw, opt);
return compileUnit;
}
private static void AddClass(CodeNamespace ns, Type t, MemberAttributes attributes, Case firstLetter)
{
// Create a type inside the namespace - public class CodeDomSample
CodeTypeDeclaration newType = new CodeTypeDeclaration(t.Name+"Wrap");
newType.Attributes = MemberAttributes.Public;
// Create a Main method which will be entry point for the class
// public static void Main
//
CodeEntryPointMethod mainmethod = new CodeEntryPointMethod();
// Add an expression inside Main -
// Console.WriteLine("Inside Main ...");
CodeMethodInvokeExpression mainexp1 = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"),
"WriteLine", new CodePrimitiveExpression("Inside Main ..."));
mainmethod.Statements.Add(mainexp1);
// Add another expression inside Main
// CodeDomSample cs = new CodeDomSample()
//
CodeStatement cs = new CodeVariableDeclarationStatement(typeof(CodeDomSample), "cs", new CodeObjectCreateExpression(new CodeTypeReference(typeof(CodeDomSample))));
mainmethod.Statements.Add(cs);
// At the end of the CodeStatements we should have constructed the following
// public static void Main() {
// Console.WriteLine("Inside Main ...");
// CodeDomSample cs = new CodeDomSample();
// }
// Create a constructor for the CodeDomSample class
// public CodeDomSample() { }
//
CodeConstructor constructor = new CodeConstructor();
constructor.Attributes = MemberAttributes.Public;
// Add an expression to the constructor
// public CodeDomSample() { Comsole.WriteLine("Inside CodeDomSample Constructor ...");
//
//CodeMethodInvokeExpression constructorexp = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "WriteLine", new CodePrimitiveExpression("Inside CodeDomSample Constructor ..."));
//constructor.Statements.Add(constructorexp);
var convconst = new CodeConstructor();
var srcvar = "s";
var p = new CodeParameterDeclarationExpression(t.Name, srcvar);
convconst.Parameters.Add(p);
convconst.Attributes = MemberAttributes.Public;
var tt = t; var addedfields = new List<string>();
while (tt != null)
{
var ti = tt.GetTypeInfo();
foreach (var m in ti.DeclaredProperties) ProcessType(addedfields,attributes, firstLetter, newType, convconst, srcvar, m.Name, m.PropertyType,false);
foreach (var m in ti.DeclaredFields) ProcessType(addedfields,attributes, firstLetter, newType, convconst, srcvar, m.Name, m.FieldType,true);
tt = ti.BaseType;
}
// Add constructor and mainmethod to type
//
newType.Members.Add(constructor);
//newType.Members.Add(mainmethod);
newType.Members.Add(convconst);
// Add the type to the namespace
//
ns.Types.Add(newType);
}
private static void ProcessType(List<string> addedfields,MemberAttributes attributes, Case firstLetter, CodeTypeDeclaration newType, CodeConstructor convconst, string srcvar, string typeName, Type mt,bool comment)
{
var ptn = mt.Name;
var ptnc = ptn;
var ptnbr = ptnc.IndexOf('[');
if (ptnbr > 0) ptnc = ptn.Substring(0, ptnbr);
var primitive = mt.IsPrimitive;
if (ptnc == "String") primitive = true;
if (ptnc == "Object") primitive = true;
if (ptnc == "Boolean") ptn = ptn.Replace("Boolean", "bool");
if (primitive && !ptn.StartsWith("Int") && !ptn.StartsWith("UInt")) ptn = FirstCharToLower(ptn);
//if (primitive) ptn = ptn.Replace("String", "string").Replace("Boolean", "bool");
//var btn = m.PropertyType.BaseType.Name;
//var utn = m.PropertyType.UnderlyingSystemType.Name;
var ctr = new CodeTypeReference(ptn);
var mn = typeName;
if (firstLetter == Case.AccessibilityBased && attributes.HasFlag(MemberAttributes.Public)) mn = FirstCharToUpper(mn);
else if (firstLetter == Case.AccessibilityBased && attributes.HasFlag(MemberAttributes.Private)) mn = FirstCharToLower(mn);
else if (firstLetter == Case.Upper) mn = FirstCharToUpper(mn);
else if (firstLetter == Case.Lower) mn = FirstCharToLower(mn);
var cmf = new CodeMemberField(ctr, mn);
cmf.Attributes = MemberAttributes.Public;
cmf.Attributes |= attributes;
if(!addedfields.Contains(mn)) if (!(mt.Name.Contains('`') || (mt.BaseType != null && mt.BaseType.Name.Contains('`'))))
{
if(comment) cmf.Comments.Add(new CodeCommentStatement("", false));
newType.Members.Add(cmf);
var convconstexp = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "WriteLine", new CodePrimitiveExpression("Inside CodeDomSample Constructor ..."));
//convconst.Parameters.Add(new CodeParameterDeclarationExpression(m.PropertyType, Strings.FirstCharToLower(mn)));
var cas = new CodeAssignStatement(new CodeVariableReferenceExpression(mn), new CodeArgumentReferenceExpression(srcvar + "." + typeName));
if (comment) convconst.Statements.Add(new CodeCommentStatement("", false));
convconst.Statements.Add(cas);
addedfields.Add(mn);
//convconst.Statements.Add(convconstexp);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment