ArgumentException: Parameter cannot be null Parameter name: original in C# code - c#

What is wrong in my code?
Whenever I try to iterate through the IEnumerable return from this CompileClasses. I got error from this line:
assembly = AppDomain.CurrentDomain.Load(memoryStream.ToArray());
But if I iterate through the object it return I don't got any compile error.
lambda_method(Closure , object , object[] )
Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(object target, object[] parameters)
public static IEnumerable<object> CompileClasses(string csharp)
{
if (string.IsNullOrEmpty(csharp))
{
throw new ArgumentNullException(nameof(csharp));
}
SyntaxTree tree = CSharpSyntaxTree.ParseText(csharp);
CompilationUnitSyntax root = tree.GetCompilationUnitRoot();
var system = SyntaxFactory.IdentifierName("System");
var systemCollections = SyntaxFactory.QualifiedName(system, SyntaxFactory.IdentifierName("Collections"));
var systemCollectionsGeneric = SyntaxFactory.QualifiedName(systemCollections, SyntaxFactory.IdentifierName("Generic"));
var systemLinq = SyntaxFactory.QualifiedName(system, SyntaxFactory.IdentifierName("Linq"));
var systemText = SyntaxFactory.QualifiedName(system, SyntaxFactory.IdentifierName("Text"));
var systemXml = SyntaxFactory.QualifiedName(system, SyntaxFactory.IdentifierName("Xml"));
var declaredUsings = root.Usings.Select(x => x.Name.ToString()).ToList();
if (!declaredUsings.Contains("System"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(system).NormalizeWhitespace());
}
if (!declaredUsings.Contains("System.Collections"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(systemCollections).NormalizeWhitespace());
}
if (!declaredUsings.Contains("System.Collections.Generic"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(systemCollectionsGeneric).NormalizeWhitespace());
}
if (!declaredUsings.Contains("System.Linq"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(systemText).NormalizeWhitespace());
}
if (!declaredUsings.Contains("System.Text"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(systemLinq).NormalizeWhitespace());
}
if (!declaredUsings.Contains("System.Xml"))
{
root = root.AddUsings(SyntaxFactory.UsingDirective(systemXml).NormalizeWhitespace());
}
tree = CSharpSyntaxTree.Create(root);
root = tree.GetCompilationUnitRoot();
var compilation = CSharpCompilation.Create("CSharp2Json",
new SyntaxTree[] { tree },
references: new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), MetadataReference.CreateFromFile(typeof(Uri).Assembly.Location), MetadataReference.CreateFromFile(typeof(DataSet).Assembly.Location), MetadataReference.CreateFromFile(typeof(EntityKey).Assembly.Location),
MetadataReference.CreateFromFile(typeof(XmlDocument).Assembly.Location)
},
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
System.Console.WriteLine(compilation);
// load compiled bits into assembly
Assembly assembly;
using (var memoryStream = new MemoryStream())
{
var result = compilation.Emit(memoryStream);
if (!result.Success)
{
throw new System.ArgumentException("Parameter cannot be null", "original");
}
assembly = AppDomain.CurrentDomain.Load(memoryStream.ToArray());
}
// instantiate object instances from assembly types
foreach (var definedType in assembly.DefinedTypes)
{
Type objType = assembly.GetType(definedType.FullName);
if (objType.BaseType?.FullName != "System.Enum")
{
object instance = null;
try
{
instance = assembly.CreateInstance(definedType.FullName);
}
catch (MissingMethodException)
{
// no default constructor - eat the exception
}
if (instance != null)
{
yield return instance;
}
}
}
}

Related

Create Class Dynamically During Runtime

Hi im trying to create a class dending on data gathered from a user input. Once its chosen id like to the create the field names and the data types based on that and fill that class with data from document effectively creating a list of that Class.
Eg I create a class called Class1 and give it 3 Properties : ID , Name , Weight and define there types as int , string , int
Then I want to fill it with data Eg : (Example in json to show structure)
ID:{
1,
2,
3
},
Name:{
A,
B,
c
},
Weight:{
10,
20,
30
}
Ive looked into Reflection and codeDom which both enable for me to make the Class but i cannot work out how to write to that new classes properties.
Code for codeDom Version:
string className = "BlogPost";
var props = new Dictionary<string, Type>() {
{ "Title", typeof(string) },
{ "Text", typeof(string) },
{ "Tags", typeof(string[]) }
};
createType(className, props);
I Create The Properties and their Types
static void createType(string name, IDictionary<string, Type> props)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "Test.Dynamic.dll", false);
parameters.GenerateExecutable = false;
var compileUnit = new CodeCompileUnit();
var ns = new CodeNamespace("Test.Dynamic");
compileUnit.Namespaces.Add(ns);
ns.Imports.Add(new CodeNamespaceImport("System"));
var classType = new CodeTypeDeclaration(name);
classType.Attributes = MemberAttributes.Public;
ns.Types.Add(classType);
foreach (var prop in props)
{
var fieldName = "_" + prop.Key;
var field = new CodeMemberField(prop.Value, fieldName);
classType.Members.Add(field);
var property = new CodeMemberProperty();
property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
property.Type = new CodeTypeReference(prop.Value);
property.Name = prop.Key;
property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
classType.Members.Add(property);
}
var results = csc.CompileAssemblyFromDom(parameters, compileUnit);
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
This is just code i found elsewhere but if this where the code i wanted id do something like
var a = new List<BlogPost>()
and then
a."Property1" = "Title 1"
Hope this is informative
You could use reflection.
Main method to create desired object and populate its properties:
public object GenerateObject(string fullyQualifiedClassName,
Dictionary<string, object> nameToValueMap)
{
var actualObject = GetInstance(fullyQualifiedClassName);
if (actualObject == null)
return actualObject;
foreach (var prop in nameToValueMap)
{
SetPropValue(actualObject, prop.Key, prop.Value);
}
return actualObject;
}
Method to create instance of the desired class, based on fully qualified class name:
public object GetInstance(string fullyQualifiedName)
{
Type type = Type.GetType(fullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(fullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
}
return null;
}
And last but not least, method to set property's value:
public bool SetPropValue<T>(T obj, string propName, object val)
{
if (string.IsNullOrEmpty(propName)) return false;
var prop = obj?.GetType()
.GetProperties()?
.FirstOrDefault(m => m.Name == propName);
if (prop != null)
{
prop.SetValue(obj, val);
return true;
}
return false;
}
Why not use dynamic object using expandoObject?
something like:
dynamic blogPost = new System.Dynamic.ExpandoObject();
blogPost.Tile = "Mary Water";
blogPost.Text= "your text here";

Get Connected Elements in Autodesk Inventor via API

We have Autodesk Inventor and created a C# Addon.
In this we loop through all Objects like this:
foreach (CurrencyAPIv2.IAssetInstance s in objects)
{
var c = s.NativeObject as ComponentOccurrence;
}
How can we get the connected Object of an Object (the one which is snapped to it). And also the Info to which connector it is connected (snapped)
Michael Navara:
Can you be more specific? CurrencyAPIv2.IAssetInstance is not a member of Inventor API
using CurrencyAPIv2 = Autodesk.Factory.PublicAPI.Currency.v2;
We solved it with the XML-files which can also be watched in AttributeHelper:
void LoadConnectors(Document document, List<ConnectionElement> connections, List<ConnectedComponent> components)
{
var am = document.AttributeManager;
var d = new Dictionary<string, string>();
var entities = am.FindObjects("*", "*");
foreach (var e in entities)
{
try
{
dynamic o = e;
foreach (AttributeSet attrS in o.AttributeSets)
{
foreach (Inventor.Attribute a in attrS)
{
d.Add(o.Name, a.Value as string);
}
}
}
catch(Exception)
{ }
}
foreach (var element in d)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(element.Value);
var connectionNodes = xmlDoc.SelectNodes("//ObjectData[#Type='42']");
var componentNodes = xmlDoc.SelectNodes("//ObjectData[#Type='38']");
// Verbindungen
if (connectionNodes.Count > 0)
{
var link1Node = xmlDoc.SelectSingleNode("//ObjectData/Link1") as XmlElement;
var link2Node = xmlDoc.SelectSingleNode("//ObjectData/Link2") as XmlElement;
var connection = new ConnectionElement();
connection.Name = element.Key;
connection.Link1 = link1Node.GetAttribute("VAL");
connection.Link2 = link2Node.GetAttribute("VAL");
connections.Add(connection);
}
// Komponenten
else if (componentNodes.Count > 0)
{
var componentConnectorNodes = xmlDoc.SelectNodes("//ObjectData/Connector");
var componentConnectors = new List<ComponentConnector>();
foreach (XmlNode cc in componentConnectorNodes)
{
var idNode = cc.SelectSingleNode("Id") as XmlElement;
var displayNameNode = cc.SelectSingleNode("DisplayName") as XmlElement;
var connector = new ComponentConnector();
connector.DisplayName = displayNameNode.GetAttribute("VAL");
connector.Id = idNode.GetAttribute("VAL");
componentConnectors.Add(connector);
}
if (components.FirstOrDefault(x => x.Name == element.Key) != null)
{
components.FirstOrDefault(x => x.Name == element.Key).Connectors.AddRange(componentConnectors);
}
else
{
var component = new ConnectedComponent();
component.Name = element.Key;
component.Connectors = new List<ComponentConnector>();
component.Connectors.AddRange(componentConnectors);
components.Add(component);
}
}
}
}

add reference to linq for CodeDomProvider

I need to compile dynamic code in C#
but it has error :
" error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'System' (are you missing an assembly reference?)"
in pResults.Errors
my code is:
try {
var className = "test1234";
CodeNamespace ns = new CodeNamespace(className);
CodeTypeDeclaration formulaClass =
new CodeTypeDeclaration(className) {
Attributes = MemberAttributes.Public
};
var constructor = new CodeConstructor { Attributes = MemberAttributes.Public };
formulaClass.Members.Add(constructor);
#region generate method
var formula = #"List<string> UsedValues1 = new List<string>();
for (int i = 0; i < 10; i++)
{
UsedValues1.Add((i * i).ToString());
}
var ttt = UsedValues1.FirstOrDefault(x => x.Contains(""2""));
return ttt;
";
var method = new CodeMemberMethod {
ReturnType = new CodeTypeReference(typeof(string)),
Name = $"M{1}",
Attributes = MemberAttributes.Public
};
method.Statements.Add(new CodeSnippetExpression($"{formula};"));
#endregion
formulaClass.Members.Add(method);
ns.Types.Add(formulaClass);
var pUnit = new CodeCompileUnit();
pUnit.Namespaces.Add(ns);
var pParams = new CompilerParameters {
GenerateInMemory = true,
};
var provider = CodeDomProvider.CreateProvider("csharp");
var pResults = provider.CompileAssemblyFromDom(pParams, pUnit);
var sw = new StringWriter();
provider.CreateGenerator(sw).GenerateCodeFromNamespace(ns, sw, new CodeGeneratorOptions() {
});
var q = sw.ToString();
if (pResults.Errors != null && pResults.Errors.Count > 0) {
return;
}
var GeneratedClass =
pResults.CompiledAssembly.CreateInstance($"{ns.Name}.{formulaClass.Name}");
var methodParams = new List<double[]>();
var ExecResult = (string)GeneratedClass.GetType().InvokeMember($"M{1}", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, GeneratedClass, methodParams.ToArray());
}
catch (Exception e) {
}

C# Compile at Runtime Visual Studio unusual behavior

Helo,
i have a strange behavior in Visual Studio.
My code is a compiling at runtime, in VS it
workts fine but if i start the programm from
release-folder the compiled dll seems to be blocked,
what is not that unusal but why does VS dont say that?
Can some one tell me also how to unload a compiled dll
in runtime?
VS:
Release-Folder:
My Test Code here:
static void Main(string[] args)
{
var property = "Value";
var key = "MyKey";
var binding = string.Format("{0}.{1}", key, property);
var dllName = string.Format("Condition_{0}_{1}.dll", key, property);
var input = "65535";
var condition = "Convert.ToInt64(input) > 0xFFFF ? 0 : 501";
for (var i = 0; i < 5; i++)
{
try
{
var conditionCompiled = BuildCondition(key, property, condition);
Type moduleType = null;
if (conditionCompiled.Errors.HasErrors)
{
if (conditionCompiled.Errors[0].ErrorNumber != "CS0042")
throw new ConditionCompileException(conditionCompiled.Errors[0].ErrorText);
var assemblyPath = Path.Combine(Directory.GetCurrentDirectory(), dllName);
var assembly = Assembly.LoadFile(assemblyPath);
moduleType = assembly.GetType("DynaCore.ConditionRunner");
}
else
{
var module = conditionCompiled.CompiledAssembly.GetModules()[0];
moduleType = module.GetType("DynaCore.ConditionRunner");
}
var method = moduleType.GetMethod("RunCondition");
var value = method.Invoke(null, new object[] { input });
Console.WriteLine("DynaCore.ConditionRunner.RunCondition({0}) => {1}", input, value);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
if (e.InnerException != null)
Console.WriteLine(e.InnerException.Message);
}
}
Console.ReadLine();
}
private static CompilerResults BuildCondition(string name, string property, string condition)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, string.Format("Condition_{0}_{1}.dll", name, property), true);
parameters.GenerateExecutable = false;
var results = csc.CompileAssemblyFromSource(parameters, string.Format(
#" using System.Linq;
using System;
using DESFireSDK.Dependency;
namespace DynaCore
{{
class ConditionRunner
{{
public static object RunCondition(string input)
{{
return {0};
}}
}}
}}"
, condition));
return results;
}

C# CodeProvider Error: Constructor on type not found

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);

Categories