Access C# Enums and Classes from other namespaces in IronPython - c#

I am stuck on what I would think should be a rather basic feature of IronPython integration with C# (this is, of course, a very simplified example). Below is a simple multi-project solution. The first project defines an enum and a class from one namespace
namespace EnumTest
{
public class EnumTest
{
public enum FooEnum
{
FooOne = 101,
FooTwo = 102,
};
public EnumTest(FooEnum f)
{
_f = f;
}
}
}
Then, I have another project which encompasses all of IronPython: the runtime DLLs, the Python modules, and the C# class that runs the python script from a file.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using IronPython.Hosting;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
namespace IronPythonRunner
{
public class IronPythonRunner
{
public IronPythonRunner()
{
ScriptEngine ironPythonEngine = Python.CreateEngine();
ScriptScope pythonScope = ironPythonEngine.CreateScope();
dynamic scope = pythonScope;
const string script = "c:/temp/try.py";
String scriptDir = Path.GetDirectoryName(script);
String ironPyDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\IronPythonDistributable\\Lib";
ICollection<String> paths = ironPythonEngine.GetSearchPaths();
paths.Add(scriptDir);
paths.Add(ironPyDir);
ironPythonEngine.SetSearchPaths(paths);
ScriptSource source = ironPythonEngine.CreateScriptSourceFromFile(script);
try
{
source.Execute(pythonScope);
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
ironPythonEngine.Runtime.Shutdown();
}
}
}
}
Finally, I have a c# project that is a test GUI for running a python script
using System;
using System.Windows.Forms;
namespace IronPythonNamespaceTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IronPythonRunner.IronPythonRunner r = new IronPythonRunner.IronPythonRunner();
}
}
}
When I try to run the following python script
print "hello world"
print str(FooEnum.FooOne)
t = EnumTest(FooEnum.FooTwo)
I get the "hello world" output, but then I get a C# IronPython.Runtime.UnboundNameException: name 'FooEnum' is not defined. Which brings me to my question, how should I be accessing the enum and the class from within my python script?

You need to import your assembly:
import clr
clr.AddReference("assembly_name")
from EnumTest import EnumTest
from EnumTest.EnumTest import FooEnum

Related

"AfterRead" event in the v2.0.0 version

My goal is to change the value of a field after it is read. And I think it is possible running the "AfterRead" event.
My current version of the library is 2.0.0.
I have tested the next getting an error:
public class sealed MyClass: INotifyRead
{
// ...
public void AfterRead(EngineBase engine, AfterReadEventArgs e)
{
}
}
The error message is:
Cannot find the namespace "AfterReadEventArgs". Missing the "using" directive or assembly reference.
I have read the next code in the docs:
FileHelperEngine engine = new FileHelperEngine(typeof(Orders));
engine.BeforeReadRecord += new BeforeReadRecordHandler(BeforeEvent);
Orders[] res = engine.ReadFile("report.txt") as Orders[];
I don't know if it is needed to declare the delegate in the source code or it is enough the declaration of the event in the Mapping Class.
Thanks a lot!
The signature of the AfterRead event is different in 2.0.0.0. Here's a working example.
using System;
using System.Diagnostics;
using FileHelpers;
namespace ConsoleApp
{
[DelimitedRecord(";")]
public sealed class MyClass : INotifyRead
{
public string Field1;
public string Field2;
public void AfterRead(EngineBase engine, string line)
{
Field1 = "ModifiedValue1";
}
}
internal class Program
{
static void Main(string[] args)
{
FileHelperEngine engine = new FileHelperEngine(typeof(MyClass));
var records = engine.ReadString("Value1;Value2");
var firstRecord = records[0] as MyClass;
Debug.Assert(firstRecord.Field1 == "ModifiedValue1");
Console.Write("All OK. Field1 had the modified value.");
Console.ReadKey();
}
}
}

error CS0116: A namespace cannot directly contain members such as fields or methods- hand writing coding using notepad

Getting the error on line 16, with the foreach. My professor wont email fast enough and the due date is in a few hours! I think I am missing a list or something. I think the d after the double is incorrect. Any help is appectiated!
using System;
using System.Windows.Forms;
using System.Collections.Generic;
public class Starbucks
{
public static void Main()
{
double[] x = {4.2, 5.7, 3.6, 9.1, 2.7, 8.4 };
}
}
static void MyGenerics(double x)
{
foreach (double d in x)
{
MessageBox.Show(x);
}
}
That's because you have defined the MyGenerics() method outside the class Starbucks. Move it inside the class. Error message is exactly telling the same thing. Your code should look like
using System;
using System.Windows.Forms;
using System.Collections.Generic;
public class Starbucks
{
public static void Main()
{
double[] x = {4.2, 5.7, 3.6, 9.1, 2.7, 8.4 };
MyGenerics(x);
}
static void MyGenerics(double[] xx)
{
foreach (double d in xx)
{
MessageBox.Show(d);
}
}
}
This problem can be caused by bad indentation. For example:
using System;
namespace Interrogacion_1.Model
{
interface IClass
{
public string Name { get; set; }
}
{
Console.WriteLine("HELLO WORLD"); #here error cs0116
}
}
The correct way would be:
using System;
namespace Interrogacion_1.Model
{
interface IClass
{
public string Name { get; set; }
public void Imprimir()
{
Console.WriteLine("HELLO WORLD");
}
}
}

MEF based plugin system can't instance my plugins

I've implemented a very small plugin system based on C# with MEF. The problem is, none of my plugins are instanced. In the Aggregate-Catalog I can see my plugin listed. But, after I'll compose these parts, there isn't my plugin in the plugin list, what I'm doing wrong?
Here's a snippet of my code:
Plugin-Loader:
[ImportMany(typeof(IFetchService))]
private IFetchService[] _pluginList;
private AggregateCatalog _pluginCatalog;
private const string pluginPathKey = "PluginPath";
...
public PluginManager(ApplicationContext context)
{
var dirCatalog = new DirectoryCatalog(ConfigurationManager.AppSettings[pluginPathKey]);
//Here's my plugin listed...
_pluginCatalog = new AggregateCatalog(dirCatalog);
var compositionContainer = new CompositionContainer(_pluginCatalog);
compositionContainer.ComposeParts(this);
}
...
And here, the plugin itself:
[Export(typeof(IFetchService))]
public class MySamplePlugin : IFetchService
{
public MySamplePlugin()
{
Console.WriteLine("Plugin entered");
}
...
}
Tested working sample.
Compile class library with code inside PluginNameSpace namespace and place it to the 'Test' folder which will be inside console app exe folder.
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Reflection;
using ConsoleApplication;
namespace ConsoleApplication
{
public interface IFetchService
{
void Write();
}
class PluginManager
{
[ImportMany(typeof(IFetchService))]
public IFetchService[] PluginList;
public PluginManager()
{
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\Test");
var pluginCatalog = new AggregateCatalog(dirCatalog);
var compositionContainer = new CompositionContainer(pluginCatalog);
compositionContainer.ComposeParts(this);
}
}
class Program
{
static void Main(string[] args)
{
var pluginManager = new PluginManager();
foreach (var fetchService in pluginManager.PluginList)
{
fetchService.Write();
}
Console.ReadKey();
}
}
}
// Separate class library
namespace PluginNameSpace
{
[Export(typeof(IFetchService))]
public class MySamplePlugin : IFetchService
{
public void Write()
{
Console.WriteLine("Plugin entered");
}
}
}

using variables from another file .cs

I have a project in c# winforms, with a file called: PublicSettings.cs (this file is within a folder called: Class) where I have a variable.
Now, I want to use that variable from another file within the same project.
PublicSettings.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LVSetup.Class
{
class PublicSettings
{
private string _ConnStr = "Connection";
public string ConnStr
{
get
{
return this._ConnStr;
}
set
{
this._ConnStr = value;
}
}
}
}
I want to use the variable ConnStr in the file: frmLogin.cs
frmLogin.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LVSetup.Class;
namespace LVSetup
{
public partial class frmLogin : Form
{
public frmLogin()
{
InitializeComponent();
}
private void btnEnter_Click(object sender, EventArgs e)
{
string a = PublicSettings.ConnStr;
}
}
}
But there is no ConnStr within PublicSettings, just (Equals and ReferenceEquals)
What could be wrong here?
You need to make this field static in order to access it without creating a class instance. Or create and instance. What suites the best depends on the logic that you want to apply for this class and how it will be used later.
Instance approach
private void btnEnter_Click(object sender, EventArgs e)
{
var settings = new PublicSettings();
string a = settings.ConnStr;
}
Static field approach
class PublicSettings
{
private static string _ConnStr = "Connection";
public static string ConnStr
{
get
{
return _ConnStr;
}
set
{
_ConnStr = value;
}
}
}
For a connection string, I would either use a Configuration file (app.config) or make the property a static read-only property (since there's often no reason to change a connection string at run-time):
class PublicSettings
{
public static string ConnStr
{
get
{
return "Connection";
}
}
}

Error with CreateInstanceAndUnwrap

I just get an error each time I run this code:
AppDomain newDomain = AppDomain.CreateDomain("newDomain");
AssemblyName assemblyName = AssemblyName.GetAssemblyName(path);
Command cmd = (Command)newDomain.CreateInstanceAndUnwrap(assemblyName.FullName, typename);
cmd.Execute();
Where path is the path of the Dll and typename is "NWT_Projekt.TestClass"
My command class:
using System;
namespace NWT_Projekt
{
public interface Command
{
void Execute();
}
}
and this is the source code of the DLL
using System;
using System.Collections;
using System.Xml;
using System.IO;
using System.Windows.Forms;
namespace NWT_Projekt
{
public class TestClass : NWT_Projekt.Command
{
public MainForm f;
public TestClass()
{
f = Form.ActiveForm as MainForm;
}
public void Execute()
{
//do something
}
}
}
ERROR (google translator :D)
An exception of type "System.Runtime.Serialization.SerializationException 'occurred in NWT PRojekt.exe.
Additional information: The type "NWT_Projekt.TestClass' in Assembly 'scripts, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null' is not marked as serializable.
EDIT2:
With the [Serializable] it works now, but after I run the code one time and then I want to create a second dll it gives me an IO error, because the file is in use!
How can I fix this?
If you want your command to run on its own appDomain, you should use MarshalByRefObject.
using System;
using System.Collections;
using System.Xml;
using System.IO;
using System.Windows.Forms;
namespace NWT_Projekt
{
public class TestClass : MarshalByRefObject, NWT_Projekt.Command
{
public MainForm f;
public TestClass()
{
f = Form.ActiveForm as MainForm;
}
public void Execute()
{
//do something
}
}
}
I advice you to prefix your interfaces : ICommand

Categories

Resources