My goal: To create a windows form application (executable) through the use of CodeDom. By this I mean I would like a form (with some code behind the form) and turn it into an executable file (as if I had gone into Visual Studio and clicked "Build" > "Build File"). Admittingly, I found this example online and I have since lightly modified it. I am getting errors while trying to generate this code - errors that I have never seen before. Furthermore, I could not find these errors on Google (odd right?)...
Here is the error I am getting:
Element type System.CodeDom.CodeExpression is not supported.
Parameter name: e
I am getting this error on the following line:
CodeProvider.GenerateCodeFromCompileUnit(Unit, writer, new CodeGeneratorOptions());
Here is my full code:
{
CodeDomProvider CodeProvider = CodeDomProvider.CreateProvider("CSharp");
// Create the Unit
CodeCompileUnit Unit = new CodeCompileUnit();
// Define a namespace and add Imports statements
CodeNamespace Namespaces = new CodeNamespace("Test.CreateForm");
Namespaces.Imports.Add(new CodeNamespaceImport("System"));
Namespaces.Imports.Add(new CodeNamespaceImport("System.Drawing"));
Namespaces.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
Namespaces.Imports.Add(new CodeNamespaceImport("System.Xml"));
Namespaces.Imports.Add(new CodeNamespaceImport("System.Data"));
Unit.Namespaces.Add(Namespaces);
// Declare the type including base type
CodeTypeDeclaration MyType = new CodeTypeDeclaration("Form1");
MyType.IsClass = true;
MyType.TypeAttributes = System.Reflection.TypeAttributes.Public;
MyType.BaseTypes.Add("System.Windows.Forms.Form");
Namespaces.Types.Add(MyType);
// Create the constructor and add code
CodeConstructor Constructor = new CodeConstructor();
Constructor.Statements.Add(
new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(),"InitializeComponent", new CodeExpression() {}));
Constructor.Attributes = MemberAttributes.Public ;
MyType.Members.Add(Constructor);
// Declare component container
MyType.Members.Add(new CodeMemberField("System.ComponentModel.IContainer", "components"));
// Implement the Dispose method
CodeMemberMethod DisposeMethod = new CodeMemberMethod();
DisposeMethod.Name = "Dispose";
DisposeMethod.Attributes = MemberAttributes.Family;
DisposeMethod.Parameters.Add(
new CodeParameterDeclarationExpression(
typeof(Boolean), "disposing"));
CodeConditionStatement Statement = new CodeConditionStatement();
Statement.Condition = new CodeArgumentReferenceExpression("disposing");
CodeConditionStatement TrueStatement = new CodeConditionStatement();
TrueStatement.Condition =
new CodeBinaryOperatorExpression(
new CodeArgumentReferenceExpression("components"),
CodeBinaryOperatorType.IdentityInequality,
new CodePrimitiveExpression(null));
TrueStatement.TrueStatements.Add(
new CodeMethodInvokeExpression(
new CodeFieldReferenceExpression(null,
"components"), "Dispose", new CodeExpression() {}));
Statement.TrueStatements.Add(TrueStatement);
DisposeMethod.Statements.Add(Statement);
DisposeMethod.Statements.Add(new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), "Dispose", new CodeArgumentReferenceExpression[]
{new CodeArgumentReferenceExpression("disposing")}));
MyType.Members.Add(DisposeMethod);
// InitializeComponent
CodeMemberMethod InitializeMethod = new CodeMemberMethod();
InitializeMethod.Name = "InitializeComponent";
InitializeMethod.Attributes = MemberAttributes.Private;
InitializeMethod.CustomAttributes.Add(
new CodeAttributeDeclaration(
"System.Diagnostics.DebuggerStepThrough"));
InitializeMethod.Statements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), "components"),
new CodeObjectCreateExpression(
new CodeTypeReference(
typeof(System.ComponentModel.Container)),
new CodeExpression() { })));
MyType.Members.Add(InitializeMethod);
// Main entry point
CodeEntryPointMethod MainMethod = new CodeEntryPointMethod();
MainMethod.Name = "Main";
MyType.Members.Add(MainMethod);
//Add mouse move event
CodeMemberEvent eventstate = new CodeMemberEvent();
eventstate.Name = "MouseMove";
eventstate.Attributes = MemberAttributes.Final | MemberAttributes.Public;
eventstate.Type = new CodeTypeReference("System.Windows.Forms.MouseEventHandler");
MyType.Members.Add(eventstate);
string OutputName = "Some.cs";
try
{
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BlankLinesBetweenMembers = true;
options.ElseOnClosing = false;
options.BracingStyle = "C";
// This is what we'll write the generated code to
IndentedTextWriter writer = new IndentedTextWriter(new StreamWriter(OutputName, false), " ");
try
{
CodeProvider.GenerateCodeFromCompileUnit(Unit, writer, new CodeGeneratorOptions());
writer.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
writer.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
// Create the compiler options
// Include referenced assemblies
CompilerParameters Options = new CompilerParameters();
Options.GenerateExecutable = true;
Options.OutputAssembly = "TestForm1.exe";
Options.CompilerOptions = "/target:winexe";
Options.MainClass = "Test.CreateForm.Form1";
string[] referenceAssemblies = { "System.dll", "System.Data.dll", "System.Drawing.dll", "System.Windows.Forms.dll", "System.XML.dll" };
Options.ReferencedAssemblies.AddRange(referenceAssemblies);
//Build and look for compiler errors
CompilerResults Result = CodeProvider.CompileAssemblyFromFile(Options, "Some.cs");
if (Result.Errors.Count > 0)
{
foreach(CompilerError ce in Result.Errors)
{
Console.WriteLine(ce.ErrorText);
}
}
else
{
Console.WriteLine("compiled successfully");
}
Console.WriteLine("press enter to continue");
Console.ReadLine();
}
You have many instances where you create an empty CodeExpression, such as in the constructor code:
// Create the constructor and add code
CodeConstructor Constructor = new CodeConstructor();
Constructor.Statements.Add(
new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(), "InitializeComponent", new CodeExpression() { }));
If you don't want to pass any parameters to the method (which is the case in the code above), simply don't pass anything (CodeMethodInvokeExpression constructor takes a params[] array, so if you don't pass anything, it means that it receives an empty array):
// Create the constructor and add code
CodeConstructor Constructor = new CodeConstructor();
Constructor.Statements.Add(
new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(),
"InitializeComponent"));
in case above code is not spitting the required code make sure you are closed the IndentedTextWriter e.g. writer.Close() enjoy..
CodeMemberMethod DisposeMethod = new CodeMemberMethod();
DisposeMethod.Name = "Dispose";
DisposeMethod.ReturnType = new CodeTypeReference(typeof(void));
DisposeMethod.Attributes = MemberAttributes.Override | MemberAttributes.Private;
DisposeMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(bool), "disposing"));
myDesignerClass.Members.Add(DisposeMethod);
CodeConditionStatement cstif2 = new CodeConditionStatement();
CodeExpression dis = new CodeVariableReferenceExpression("disposing");
CodeExpression comp = new CodeVariableReferenceExpression("components");
cstif2.Condition = new CodeBinaryOperatorExpression(dis, CodeBinaryOperatorType.BooleanAnd, new CodeBinaryOperatorExpression(dis, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)));
CodeExpression dispos = new CodeMethodInvokeExpression(comp, "Dispose", new CodeExpression[] { });
cstif2.TrueStatements.Add(dispos);
DisposeMethod.Statements.Add(cstif2);
CodeExpression bdispos = new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), "Dispose", new CodeExpression[] { });
DisposeMethod.Statements.Add(bdispos);
Replace () after CodeExpression with [] and error will vanish.
Related
I am generating dynamic class with dynamic fields. I created fields but cant validate them.
So far I did,
CodeMemberProperty property1 = new CodeMemberProperty();
property1.Name = "StringProperty";
property1.Type = new CodeTypeReference("System.String");
property1.Attributes = MemberAttributes.Public;
property1.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "testStringField") ) );
property1.SetStatements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "testStringField"), new CodePropertySetValueReferenceExpression()));
this will generate class property but I need to validate it.
Expected output:
[Required]
public string FieldName {get;set;}
I guess you should be doing something like
CodeMemberField field = new CodeMemberField();
field.Name = "myField";
field.Type = new CodeTypeReference("System.String");
field.Attributes = MemberAttributes.Private;
field.InitExpression = new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(),
field.Name),
CodeBinaryOperatorType.Assign,
new CodePrimitiveExpression("Hello world"));
CodeMemberProperty prop = new CodeMemberProperty();
prop.Name = "myproperty";
prop.Type = field.Type;
prop.Attributes = MemberAttributes.Public;
prop.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(),
field.Name)));
prop.SetStatements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(),
field.Name),
new CodePropertySetValueReferenceExpression()));
prop.CustomAttributes.Add(
new CodeAttributeDeclaration(
new CodeTypeReference("Required")));
Is it doing what you expect ? What else do you mean by validation ?
I'm trying to create a simple dll runtime, using CodeDOM.
I have quite understand what I need to finish this simple test application.
I need to create with CodeDOM object this statement:
List<string> test = new List<string>() {"A", "B", ... }
I'm just having this statement for declaration of a List of n values, but find nowhere the instructions for reach what I need.
This is my actual code:
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace samples = new CodeNamespace("ClassLibrary1");
compileUnit.Namespaces.Add(TestNamespace);
samples.Imports.Add(new CodeNamespaceImport("System"));
samples.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
samples.Imports.Add(new CodeNamespaceImport("System.Text"));
CodeTypeDeclaration _class = new CodeTypeDeclaration("TestClass");
CodeMemberField _field = new CodeMemberField();
_field.Attributes = MemberAttributes.Private;
_field.Name = "_testMember";
_field.Type = new CodeTypeReference(typeof(List<string>));
//This is where I cannot understand how to insert the values
_field.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(List<string>)), new CodePrimitiveExpression(64));
class1.Members.Add(_field);
How to initialize a list (or an array) with some default values?
Thank you in advance.
As suggested, the answer lies in CodeArrayCreateExpression.
Here is the completed (working) code snippet:
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace samples = new CodeNamespace("ClassLibrary1");
compileUnit.Namespaces.Add(samples);
samples.Imports.Add(new CodeNamespaceImport("System"));
samples.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
samples.Imports.Add(new CodeNamespaceImport("System.Text"));
CodeTypeDeclaration _class = new CodeTypeDeclaration("TestClass");
CodeMemberField _field = new CodeMemberField();
_field.Attributes = MemberAttributes.Private;
_field.Name = "_testMember";
_field.Type = new CodeTypeReference(typeof(List<string>));
var initialiseExpression = new CodeArrayCreateExpression(
new CodeTypeReference(typeof(string)),
new CodePrimitiveExpression("A"),
new CodePrimitiveExpression("B"),
new CodePrimitiveExpression("C"));
_field.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(List<string>)), initialiseExpression);
_class.Members.Add(_field);
The important part is the new initialiseExpression variable that defines the array.
I get the error: Constructor on type 'SimpleScript.Generator' not found.
I tried passing the correct parameters but i still get this error, this is my source code, and the script is a very simple piece of code that generates the Array of Element head and body. And also it is compiled successfully but it throws the error at the execution line.
string source = #"
using System;
using MSiteDLL;
namespace SimpleScript
{
public static class Generator
{
public static Document Generate(Data server)
{
"+script+ #"
Block[] blocks = {
new Block(""head"", head),
new Block(""body"", body),
};
return new Document(blocks);
}
}
}
";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v4.0"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
ReferencedAssemblies = {
"System.dll",
"System.Core.dll",
"MSiteDLL.dll",
}
};
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
{
string output = "";
foreach (CompilerError y in results.Errors)
{
output += y.ErrorText + Environment.NewLine;
}
throw new Exception("Compile failed:" + output);
}
object o = results.CompiledAssembly.CreateInstance("SimpleScript.Generator");
MethodInfo mi = o.GetType().GetMethod("Generate");
Data[] parametersArray = new Data[] { server };
Document x = (Document)mi.Invoke(o, parametersArray);
return x;
Since your class is static, you should invoke the method in a static way.
So first, remove this line:
object o = results.CompiledAssembly.CreateInstance("SimpleScript.Generator");
And use those to invoke:
MethodInfo mi = Type.GetType("SimpleScript.Generator").GetMethod("Generate");
Data[] parametersArray = new Data[] { server };
Document x = (Document)mi.Invoke(null, parametersArray);
I'd like to know how to create the following XML using SharpKml:
<StyleMap id="msn_placemark_circle">
<Pair>
<key>normal</key>
<styleUrl>#sn_placemark_circle</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#sh_placemark_circle_highlight</styleUrl>
</Pair>
</StyleMap>
I've tried several things, but with no success. This is what I have so far:
public static StyleSelector Generate_M_ylw_pushpin3()
{
var stylemap = new StyleMapCollection();
stylemap.Id = "s_ylw-pushpin3";
var normalPair = new Pair();
normalPair.Id = "normal";
normalPair.Selector = StyleGenerator.Generate_s_ylw_pushpin_hl3();
//normalPair.StyleUrl = new Uri(#sh_placemark_circle_highlight); // Exception by .NET
var highlightPair = new Pair();
highlightPair.Id = "highlight";
highlightPair.Selector = StyleGenerator.Generate_s_ylw_pushpin_hl3();
//highlightPair.StyleUrl = new Uri(#sh_placemark_circle_highlight); // Exception by .NET
stylemap.Add(normalPair);
stylemap.Add(highlightPair);
return stylemap;
}
// This code just works fine
public static StyleSelector Generate_s_ylw_pushpin_hl3()
{
var style = new Style();
style.Id = "s_ylw-pushpin_hl3";
var iconStyle = new IconStyle();
iconStyle.Color = Color32.Parse("ff00ff00");
iconStyle.Scale = 1.18182;
iconStyle.Icon = new IconStyle.IconLink(new Uri("http://some/url"));
var labelStyle = new LabelStyle();
labelStyle.Color = Color32.Parse("00ffffff");
style.Icon = iconStyle;
style.Label = labelStyle;
return style;
}
Who knows on how to achieve this?
I've find the answer to my own question:
public static StyleSelector Generate_M_ylw_pushpin3()
{
var stylemap = new StyleMapCollection();
stylemap.Id = "s_ylw-pushpin3";
var normalPair = new Pair();
normalPair.StyleUrl = new Uri("#sh_placemark_circle", UriKind.Relative);
normalPair.State = StyleState.Normal;
var highlightPair = new Pair();
highlightPair.StyleUrl = new Uri("#sh_placemark_circle_highlight", UriKind.Relative);
highlightPair.State = StyleState.Highlight;
stylemap.Add(normalPair);
stylemap.Add(highlightPair);
return stylemap;
}
Martijin added the answer to his own question, which is amazing and helped me get to my solution. Just for an alternative that I believe is slightly more generic I figured I'd drop my solution that I got to thanks to Martijin's answer.
Note: my solution is generating these for a line object to be generated, however this could be used for other styles easily
Creating the style objects for a highlight or normal state. The objects made here are what will be added to the stylemap
Here we just pass in the placemark itself (with some details such as the placemark name, etc., available) and a boolean value as to whether it is a highlight or normal style. My usage is thus:
kmlDom.Style normalStyle = createPlacemarkLineStyle(thisPlacemark, false);
kmlDom.Style highlightStyle = createPlacemarkLineStyle(thisPlacemark, true);
Method:
public kmlDom.Style createPlacemarkLineStyle ( kmlDom.Placemark placemark , bool highlight )
{
kmlDom.Style styleNode = new kmlDom.Style( );
// Add Line Style
kmlDom.LineStyle lineStyle = new kmlDom.LineStyle( );
if( !highlight )
{
styleNode.Id = String.Format( "{0}-normal", placemark.placemarkName );
lineStyle.Color = hexToColor("ff0000ff");
lineStyle.Width = 2;
}
else
{
styleNode.Id = String.Format( "{0}-highlight", placemark.placemarkName );
lineStyle.Color = hexToColor( "ff0000ff" );
lineStyle.Width = 2;
}
styleNode.Line = lineStyle;
return styleNode;
}
Now we create the style selector to be added to the placemark object
Here I pass two style objects and the original placemark object to create the full style map. This is returned to the placemark with a call such as:
thisPlacemark.StyleSelector = createPlacemarkLineStyleMap(placemark, normalStyle, highlightStyle);
Method:
public kmlDom.StyleSelector createPlacemarkLineStyleMap ( kmlDom.Placemark placemark , kmlDom.Style normalStyle , kmlDom.Style highlightStyle )
{
// Set up style map
kmlDom.StyleMapCollection styleMapCollection = new kmlDom.StyleMapCollection( );
styleMapCollection.Id = String.Format( "{0}-stylemap" , placemark.placemarkName );
// Create the normal line pair
kmlDom.Pair normalPair = new kmlDom.Pair();
normalPair.StyleUrl = new Uri(String.Format("#{0}", normalStyle.Id), UriKind.Relative);
normalPair.State = kmlDom.StyleState.Normal;
// Create the highlight line pair
kmlDom.Pair highlightPair = new kmlDom.Pair( );
highlightPair.StyleUrl = new Uri( String.Format( "#{0}" , highlightStyle.Id ) , UriKind.Relative );
highlightPair.State = kmlDom.StyleState.Highlight;
// Attach both pairs to the map
styleMapCollection.Add( normalPair);
styleMapCollection.Add( highlightPair );
return styleMapCollection;
}
Why I have kmlDom, kmlBase, and kmlEngine in front of my object types
** My usings are as follows to separate sharpkml objects from my own internal objects
using kmlBase = SharpKml.Base;
using kmlDom = SharpKml.Dom;
using kmlEngine = SharpKml.Engine;
Is it possible to build a Yaml document dynamically from c# with Yaml.DotNet or another library?
I understand how this can be done using serialisation, however that requires starting with an object structure.
I'm looking to find a way to create the Yaml document nodes on the fly as you would with Xml using the XElement.Add(object) method for example.
You can do that using YamlDotNet. You start by creating a YamlStream, add one or more document to it, then you can add sequences, mappings and scalars to it.
Here is an example on how to do it:
var address = new YamlMappingNode(
new YamlScalarNode("street"),
new YamlScalarNode("123 Tornado Alley\nSuite 16") { Style = YamlDotNet.Core.ScalarStyle.Literal },
new YamlScalarNode("city"),
new YamlScalarNode("East Westville"),
new YamlScalarNode("state"),
new YamlScalarNode("KS")
) { Anchor = "main-address" };
var stream = new YamlStream(
new YamlDocument(
new YamlMappingNode(
new YamlScalarNode("repeipt"),
new YamlScalarNode("Oz-Ware Purchase Invoice"),
new YamlScalarNode("date"),
new YamlScalarNode("2007-08-06"),
new YamlScalarNode("customer"),
new YamlMappingNode(
new YamlScalarNode("given"),
new YamlScalarNode("Dorothy"),
new YamlScalarNode("family"),
new YamlScalarNode("Gale")
),
new YamlScalarNode("items"),
new YamlSequenceNode(
new YamlMappingNode(
new YamlScalarNode("part_no"),
new YamlScalarNode("A4786"),
new YamlScalarNode("descrip"),
new YamlScalarNode("Water Bucket (Filled)"),
new YamlScalarNode("price"),
new YamlScalarNode("1.47"),
new YamlScalarNode("quantity"),
new YamlScalarNode("4")
),
new YamlMappingNode(
new YamlScalarNode("part_no"),
new YamlScalarNode("E1628"),
new YamlScalarNode("descrip"),
new YamlScalarNode("High Heeled \"Ruby\" Slippers"),
new YamlScalarNode("price"),
new YamlScalarNode("100.27"),
new YamlScalarNode("quantity"),
new YamlScalarNode("1")
)
),
new YamlScalarNode("bill-to"), address,
new YamlScalarNode("ship-to"), address,
new YamlScalarNode("specialDelivery"),
new YamlScalarNode("Follow the Yellow Brick\n" +
"Road to the Emerald City.\n" +
"Pay no attention to the\n" +
"man behind the curtain.")
{
Style = YamlDotNet.Core.ScalarStyle.Literal
}
)
)
);
I've now worked out how to do this using Yaml.Net. The YamlStream needs to be loaded with some initial content using the Load() method.
const string initialContent = "---\nversion: 1\n...";
var sr = new StringReader(initialContent);
var stream = new YamlStream();
stream.Load(sr);
You can then cast the RootNode of the YamlDocument to YamlMappingNode which has an Add method.
var rootMappingNode = (YamlMappingNode)stream.Documents[0].RootNode;
rootMappingNode.Add("shout", "yay!");
You can then add a variety of node types before saving:
var props = new YamlMappingNode();
props.Add("prop1", "value1");
props.Add("prop2", "value2");
rootMappingNode.Add("itemWithProps", props);
var props2 = new YamlMappingNode();
props2.Add("prop1", "value1");
props2.Add("prop2", "value2");
var props3 = new YamlMappingNode();
props3.Add("prop1", "value1");
props3.Add("prop2", "value2");
var seq = new YamlSequenceNode();
seq.Add(props2);
seq.Add(props3);
rootMappingNode.Add("sequenceOfItems", seq);
var col = new YamlSequenceNode();
col.Style = SequenceStyle.Flow;
col.Add("a");
col.Add("b");
col.Add("c");
var seqMapping = new YamlMappingNode();
seqMapping.Add("collection", col);
seq.Add(seqMapping);
using (TextWriter writer = File.CreateText("C:\\temp\\test.yaml"))
stream.Save(writer, false);
The output from this example is:
version: 1
shout: yay!
itemWithProps:
prop1: value1
prop2: value2
sequenceOfItems:
- prop1: value1
prop2: value2
- prop1: value1
prop2: value2
- collection: [a, b, c]
...
Thanks to #Antoine Aubry for creating Yaml.Net and vaguely pointing me in right direction.