Equivalent code of CreateObject in C# - c#

I have a code in VB6. Can anyone tell me how to write it in C#. This code is below:
Set Amibroker = CreateObject("Broker.Application")
Set STOCK = Amibroker.Stocks.Add(ticker)
Set quote = STOCK.Quotations.Add(stInDate)
quote.Open = stInOpen
quote.High = stInHigh
quote.Low = stInlow
quote.Close = stInYcp
quote.Volume = stInVolume
Set STOCK = Nothing
Set quote = Nothing
What is the equivalent of CreateObject in C#?. I try to add references to com object but i can't find any com object as Broker.Application or amibroker

If you are using .net 4 or later, and therefore can make use of dynamic, you can do this quite simply. Here's an example that uses the Excel automation interface.
Type ExcelType = Type.GetTypeFromProgID("Excel.Application");
dynamic ExcelInst = Activator.CreateInstance(ExcelType);
ExcelInst.Visible = true;
If you can't use dynamic then it's much more messy.
Type ExcelType = Type.GetTypeFromProgID("Excel.Application");
object ExcelInst = Activator.CreateInstance(ExcelType);
ExcelType.InvokeMember("Visible", BindingFlags.SetProperty, null,
ExcelInst, new object[1] {true});
Trying to do very much of that will sap the lifeblood from you.
COM is so much easier if you can use early bound dispatch rather than late bound as shown above. Are you sure you can't find the right reference for the COM object?

If you use .NET Framework 4.0 and above, you can use this pattern:
public sealed class Application: MarshalByRefObject {
private readonly dynamic _application;
// Methods
public Application() {
const string progId = "Broker.Application";
_application = Activator.CreateInstance(Type.GetTypeFromProgID(progId));
}
public Application(dynamic application) {
_application = application;
}
public int Import(ImportType type, string path) {
return _application.Import((short) type, path);
}
public int Import(ImportType type, string path, string defFileName) {
return _application.Import((short) type, path, defFileName);
}
public bool LoadDatabase(string path) {
return _application.LoadDatabase(path);
}
public bool LoadLayout(string path) {
return _application.LoadLayout(path);
}
public int Log(ImportLog action) {
return _application.Log((short) action);
}
public void Quit() {
_application.Quit();
}
public void RefreshAll() {
_application.RefreshAll();
}
public void SaveDatabase() {
_application.SaveDatabase();
}
public bool SaveLayout(string path) {
return _application.SaveLayout(path);
}
// Properties
public Document ActiveDocument {
get {
var document = _application.ActiveDocument;
return document != null ? new Document(document) : null;
}
}
public Window ActiveWindow {
get {
var window = _application.ActiveWindow;
return window != null ? new Window(window) : null;
}
}
public AnalysisDocs AnalysisDocs {
get {
var analysisDocs = _application.AnalysisDocs;
return analysisDocs != null ? new AnalysisDocs(analysisDocs) : null;
}
}
public Commentary Commentary {
get {
var commentary = _application.Commentary;
return commentary != null ? new Commentary(commentary) : null;
}
}
public Documents Documents {
get {
var documents = _application.Documents;
return documents != null ? new Documents(documents) : null;
}
}
public string DatabasePath {
get { return _application.DatabasePath; }
}
public bool Visible {
get { return _application.Visible != 0; }
set { _application.Visible = value ? 1 : 0; }
}
public string Version {
get { return _application.Version; }
}
}
}
Next you must wrap all AmiBroker OLE Automation classes. For example wrap Commentary class:
public sealed class Commentary : MarshalByRefObject {
// Fields
private readonly dynamic _commentary;
// Methods
internal Commentary(dynamic commentary) {
_commentary = commentary;
}
public void Apply() {
_commentary.Apply();
}
public void Close() {
_commentary.Close();
}
public bool LoadFormula(string path) {
return _commentary.LoadFormula(path);
}
public bool Save(string path) {
return _commentary.Save(path);
}
public bool SaveFormula(string path) {
return _commentary.SaveFormula(path);
}
}

Here's a snippet from the C# code I used to automate Amibroker (from when I went down that path). You'll need to reference System.Runtime.Interopservices
System.Type objType = System.Type.GetTypeFromProgID("Broker.Application");
dynamic comObject = System.Activator.CreateInstance(objType);
comObject.Import(0, fileName, "default.format");
comObject.RefreshAll();
Typing a dot won't bring up the comObject internal methods, though.
All I can say about this method is - it works, like a charm, but stay away from it, like David said. I got my inspiration for this method from:
http://www.codeproject.com/Articles/148959/How-the-new-C-dynamic-type-can-simplify-access-to
For another angle of attack, you may want to check out (I think this is early binding):
http://adamprescott.net/2012/04/05/net-vb6-interop-tutorial/
Hope at least some of this help you. I've used both these methods with Amibroker and C#, but I ended up leaving them behind. COM and Amibroker don't mix well. Even TJ says so.
Good luck anyway.

ami2py will read AmiBroker data into python. The current version is .0.8.1 WARNING: It only provides day resolution on data.
The following few lines of code will read a symbol from AmiBroker into a pandas df
import pandas
import ami2py
folder='C:/Program Files/AmiBroker/Databases/StockCharts'
symbol='indu'
df = pandas.DataFrame()
symbolData = ami2py.AmiDataBase(folder).get_dict_for_symbol(symbol)
for z in ['Year', 'Month', 'Day', 'Open', 'High', 'Low', 'Close', 'Volume'] :
df[symbol+':'+z] = symbolData[z]
print(df.describe())

Related

Is there a construct or pattern similar to C# `using` which will return an object?

I have a WCF message inspector which inspects requests and responses: Message. The inspector works fine. A Message object can only be read once so once you read it, you cannot simply propagate as WCF will complain that the message has been read. Therefore, I am creating a brand new copy of the message and propagating that.
I have designed a class that allows message reading and after the caller has read whatever they want, they need to call Close which will return a copy of the message. Here is the skeleton of my class:
using System.ServiceModel.Channels;
internal abstract class MessageReader
{
internal string ReadSomething(string id)
{
// Return string
}
internal string ReadSomethingElse(string id)
{
// Return string
}
internal Message Close()
{
// Create copy and return it.
}
}
Users of my class may forget to call Close() which is fine because WCF will yell at them. Right now I have documentation to let users know they need to call Close().
Here is the question
Is there a pattern, or something similar, to C#'s using construct but one which returns an object at the end? This will be really convenient because then users of my class can just use a construct like that and at the end it will return the copy of the message. Something like this:
UsingSomeConstruct(var reader = new MessageReader(ref originalMessage))
{
var a = reader.ReadSomething("something");
var b = reader.ReadSomethingElse("something");
// Do something with what was read
}
// At this point originalMessage will be the copy of the message and no longer the original message.
EDIT
I thought about hacking IDisposable to achieve this but I am NOT going to do it that way so looking for other ideas.
There is no such language construct of course.
What I could suggest is to use IDisposable for cleaning up, and add ref Message message argument to each ReadXXX method. I know it will not be so convenient for your users, but from the other side they cannot forget passing the parameter.
So the implementation would be something like this:
internal class MessageReader : IDisposable
{
private MessageBuffer buffer;
private Message message;
private void Release()
{
if (buffer == null) return;
buffer.Close();
buffer = null;
message = null;
}
protected void OnReadRequest(ref Message message)
{
if (message == null) throw new ArgumentNullException("message");
if (this.message == message) return;
Release();
this.buffer = message.CreateBufferedCopy(int.MaxValue);
message = this.message = buffer.CreateMessage();
}
public void Dispose()
{
Release();
}
internal string ReadSomething(ref Message message, string id)
{
OnReadRequest(ref message);
// Return string
}
internal string ReadSomethingElse(ref Message message, string id)
{
OnReadRequest(ref message);
// Return string
}
}
and the sample usage:
using (var reader = new MessageReader())
{
var a = reader.ReadSomething(ref originalMessage, "something");
var b = reader.ReadSomethingElse(ref originalMessage, "something");
// Do something with what was read
}
// At this point originalMessage will be the copy of the message and no longer the original message.
The way I'd do this is as follows:
public MessageReader: IDisposable
{
public static MessageReader Create(ref Message message)
{
var buffer = message.CreateBufferedCopy(/*whatever is fit*/);
try
{
var reader = new MessageReader(buffer);
message = buffer.CreateMessage();
return reader;
}
catch
{
buffer.Close();
throw;
}
}
private readonly MessageBuffer buffer;
private bool disposed;
private MessageReader(MessageBuffer buffer) { this.buffer = buffer; }
public void Dispose()
{
if (disposed)
return;
buffer.Close();
disposed = true;
}
public string Read(string id)
{
var newCopy = buffer.CreateMessage();
//work with new copy...
}
}
And you'd simply use it like this:
using (var reader = MessageReader.Create(ref message))
//message here is already an untouched copy with no need of user active
//intervention and is never touched again by the reader.
{
var a = reader.Read("something"); //reads copy
...
}
IMHO, this is as clean as it can be. Note that MessageReader implements IDisposable exclusively because it holds a reference to the disposable private MessageBuffer.
Thanks to all the help from #InBetween, #quetzalcoatl, and #Ivan Stoev. Upvoted your answers because it helped me arrive at the following.
In the constructor, I create a copy of the message and set the original message to the copy. Since the status of this message is Created WCF will be happy propogating it. I create another copy and use that for reading multiple times.
#Ivan said but what if the user does not ask for anything to be read then the copying was wasted work. That is a good point but in my case, this is an interceptor and all messages are intercepted to be read.
Here is the code I ended up with suggestions from all of you:
public class MessageReader : IDisposable {
private readonly Message message;
public MessageReader(ref Message originalMessage) {
using( var buffer = originalMessage.CreateBufferedCopy( int.MaxValue ) ) {
// Keep original message for reading
this.message = buffer.CreateMessage();
// Set original message to a copy of the original
originalMessage = buffer.CreateMessage();
}
}
public int ReadSomething(string id) {
// Read from this.message;
}
public int ReadSomethingElse(string id) {
// Read from this.message;
}
public void Close() {
this.Dispose();
}
public void Dispose() {
this.message.Close();
}
}
The caller can either use it in a using block or without it. The using block is used for good reasons and not as a hack.
public object AfterReceiveRequest(ref Message request, IClientChannel channel,
InstanceContext instanceContext) {
try {
using( var rdr = new MessageReader(ref request) ) {
var value= rdr.ReadSomething( someIdentifier );
return value;
}
}
catch( System.Exception ex ) {
throw CreateFault( ex, request );
}
}
Nope, there is no such construct. It is simply too specific to exist there out of the box. There are extension methods which often are very helpful, but you won't be able to use them on this ref Message parameter..
However, if you are willing to use ref at all, then why dont simply include all that logic it in Reader's constructor?
Here's an example, somewhat contrived, but it should show what I mean. Like others mentioned in comments, I also suggest implementing IDisposable on the Reader object instead of Close, so I included that already.
TL;DR: In example below, the most important thing is in Reader(ref msg) constructor which clones the message, copies the data, and replaces the original message with a safe-message class which can be read many times..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
// real-world variables, keep them typed as base Message
// to be able to silently replace them with different objects
Message original1;
Message original2;
// let's construct some one-time readable messages
{
var tmp1 = new OneTimeMessage();
tmp1.data["mom"] = "dad";
tmp1.data["cat"] = "dog";
original1 = tmp1;
var tmp2 = new OneTimeMessage();
tmp2.data["mom"] = "dad";
tmp2.data["cat"] = "dog";
original2 = tmp2;
}
// test1 - can't read twice
Console.WriteLine("test0A:" + original1.GetData("mom"));
//Console.WriteLine("test0B:" + original1.GetData("mom")); // fail
// test2 - can read twice with Reader's help
var backup1 = original2;
using(var rd1 = new Reader(ref original2))
{
Console.WriteLine("test1A:" + rd1.ReadSomething("mom"));
}
var backup2 = original2;
using(var rd2 = new Reader(ref original2))
{
Console.WriteLine("test1A:" + rd2.ReadSomething("mom"));
//^ ok - becase Reader replaced 'original2' with SafeMessage
}
// test3: Reader's ctor is intelligent
// so no more SafeMessages created during future usage
var backup3 = original2;
using(var rd3 = new Reader(ref original2))
{
}
var backup4 = original2;
using(var rd4 = new Reader(ref original2))
{
}
Console.WriteLine("checking for copies:" + (original2 == backup1));
Console.WriteLine("checking for copies:" + (original2 == backup2));
Console.WriteLine("checking for copies:" + (original2 == backup3));
Console.WriteLine("checking for copies:" + (original2 == backup4));
}
}
}
public abstract class Message
{
public abstract string GetData(string id);
}
public class OneTimeMessage : Message // this models your current one-time-readable message
{
public IDictionary<string, string> data = new Dictionary<string, string>();
public override string GetData(string id)
{
var tmp = data[id];
data.Remove(id);
// that's nonsense, but I want to show that you can't
// read the same thing twice from this object
return tmp;
}
}
public class SafeMessage : Message
{
public IDictionary<string, string> data;
public override String GetData(string id)
{
return data[id];
}
public SafeMessage(Message msg)
{
// read out the full msg's data and store it
// since this is example, we can do it in a pretty simple way
// in your code that will probably be more complex
this.data = new Dictionary<string,string>(((OneTimeMessage)msg).data);
}
}
public class Reader : IDisposable
{
private Message message;
public Reader(ref Message src)
{
src = src is SafeMessage ? src : new SafeMessage(src);
this.message = src;
}
public string ReadSomething(string id){ return message.GetData(id); }
public void Dispose(){ Close(); }
public void Close(){ message=null; Console.WriteLine("reader closed"); }
}
EDIT: improved example
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text.RegularExpressions;
using System.Xml;
namespace MyProgram
{
public class Program
{
public static void Main(string[] args)
{
// real-world variables, keep them typed as base Message
// to be able to silently replace them with different objects
Message original1;
Message original2;
// let's construct some one-time readable messages
{
original1 = new TheMessage("dad", "dog");
original2 = new TheMessage("dad", "dog");
}
// test1 - can't read twice
Console.WriteLine("test0A:" + original1.GetReaderAtBodyContents().ReadOuterXml());
// Console.WriteLine("test0B:" + original1.GetReaderAtBodyContents().ReadOuterXml()); // fail: InvalidOperationException - it was already read
// test2 - can read ONCE with Reader's help, but the message is replaced and is usable again
var backup1 = original2;
using (var rd1 = new ReaderOnce(ref original2))
{
Console.WriteLine("is message replaced after opening Reader:" + (original2 != backup1));
Console.WriteLine("test1A:" + rd1.ReadBodyXml());
// Console.WriteLine("test1B:" + rd1.ReadBodyXml()); // fail: InvalidOperationException - it was already read
}
// test3 - can read MANY TIMES with ReaderMany's help
// also note we use 'original2' again, which was already used above, so in fact ReaderOnce really works as well
var backup2 = original2;
using (var rd1 = new ReaderMany(ref original2))
{
Console.WriteLine("is message replaced after opening Reader:" + (original2 != backup2));
Console.WriteLine("test2A:" + rd1.ReadBodyXml());
Console.WriteLine("test2B:" + rd1.ReadBodyXml()); // ok
}
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
// solution1
public class ReaderOnce : IDisposable
{
private Message localCopy;
public ReaderOnce(ref Message src)
{
// create a WCF MessageBuffer to assist in copying messages
// btw. I suppose you should set some sane limit instead of that below
using (var tempBuffer = src.CreateBufferedCopy(int.MaxValue))
{
src = tempBuffer.CreateMessage(); // FIRST copy for outer use
localCopy = tempBuffer.CreateMessage(); // SECOND copy for internal use in the Reader
}
}
public void Dispose() { Close(); }
public void Close()
{
localCopy.Close(); // but that does NOT affect FIRST copy sent to outer scope outside reader
Console.WriteLine("reader closed");
}
public string ReadBodyXml() // careful: that's again ONE TIME readable
{
return localCopy.GetReaderAtBodyContents().ReadOuterXml();
}
}
// solution2
public class ReaderMany : IDisposable
{
private MessageBuffer localBuffer;
public ReaderMany(ref Message src)
{
localBuffer = src.CreateBufferedCopy(int.MaxValue);
src = localBuffer.CreateMessage(); // FIRST copy for outer use
}
public void Dispose() { Close(); }
public void Close()
{
localBuffer.Close();
Console.WriteLine("reader closed");
}
public string ReadBodyXml() // this is readable multiple times
{
using (var tmp = localBuffer.CreateMessage())
return tmp.GetReaderAtBodyContents().ReadOuterXml();
}
}
// let's fake some Message type to have something to test the Reader on
public class TheMessage : Message
{
public override MessageHeaders Headers => _mh;
public override MessageProperties Properties => _mp;
public override MessageVersion Version => _mv;
private MessageHeaders _mh;
private MessageProperties _mp;
private MessageVersion _mv;
private string data1;
private string data2;
// btw. below: surprise! XmlDictionaryWriter is in "System.Runtime.Serialization", not in "System.Xml"
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("foo");
writer.WriteAttributeString("data1", data1);
writer.WriteAttributeString("data2", data2);
writer.WriteEndElement();
}
public TheMessage(string data1, string data2)
{
// remember, this class is just an example, you will work on your own messages you already have
_mv = MessageVersion.Soap12;
_mh = new MessageHeaders(_mv);
_mp = new MessageProperties();
// below: yeah, that's super-naive and wrong, but that's an example
this.data1 = data1;
this.data2 = data2;
}
}
There is no language construct in c# that does what you are asking. As stated in comments, you could abuse IDisposable and the language and use a using block to achieve what you want.
But, I fail see what you are gaining, you are just punting the problem; now users will need to remember to use usinginstead of Close. The latter is simple and clean, the former uses a very known language construct to do something different to what it was thought for, something that will potentially be very confusing.

Need to access a serial port from different classes

I am using a serial port object that was generated by the designer in C# (non static).
I need to be able to access it from methods that are static in different classes (I know it is a bad practice but that is what I inherit)
The port access use the below code.
public bool Read_Board_Port()
{
byte[] bData = new byte[256];
string message;
bool sucess = false;
try
{
if (!(serialBoardPort.IsOpen == true))
Connect_To_Board(Globals.BoardportName, Globals.BoardbaudRate, Globals.Boardparity, Globals.BoardstopBits, Globals.BoarddataBits);
if(CMDDirect || Globals.HostCommandString)
{
serialBoardPort.ReadTimeout = 1000; // Timeout if no answer from the port.
message = serialBoardPort.ReadLine();
Globals.RXBoardBuff = Encoding.UTF8.GetBytes(message);
Write_To_Console_Dr(message);
sucess = true;
}
else
{
serialBoardPort.Read(Globals.RXBoardBuff, 0, Constants.RXBOARDBUFFSIZE);
if (Check_Command_Correct(Globals.RXBoardBuff, Globals.CommandOut))
sucess = true;
else
{
Write_Error_To_Console_Dr(Constants.ERRORDATAFROMBOARDPORT);
sucess = false;
}
}
}
catch
{
MessageBox.Show(Constants.ERRORNODATABOARPORT);
sucess = false;
}
return sucess;
}
If I declare new a different instance of the serial port will be used, I need to use the port that is already open.
Thanks
As stated by #Matthew Spencer you should pass the serial port as a parameter to the static methods that needs it. First create a method on your board class or whatever its name is that returns the instance of your serial port. Then use it to get the serial port for use to the static methods you mentioned.
Something like this should be what you need..
public bool Read_Board_Port()
{
byte[] bData = new byte[256];
string message;
bool sucess = false;
try
{
if (!(serialBoardPort.IsOpen == true))
Connect_To_Board(Globals.BoardportName, Globals.BoardbaudRate, Globals.Boardparity, Globals.BoardstopBits, Globals.BoarddataBits);
if(CMDDirect || Globals.HostCommandString)
{
serialBoardPort.ReadTimeout = 1000; // Timeout if no answer from the port.
message = serialBoardPort.ReadLine();
Globals.RXBoardBuff = Encoding.UTF8.GetBytes(message);
Write_To_Console_Dr(message);
sucess = true;
}
else
{
serialBoardPort.Read(Globals.RXBoardBuff, 0, Constants.RXBOARDBUFFSIZE);
if (Check_Command_Correct(Globals.RXBoardBuff, Globals.CommandOut))
sucess = true;
else
{
Write_Error_To_Console_Dr(Constants.ERRORDATAFROMBOARDPORT);
sucess = false;
}
}
}
catch
{
MessageBox.Show(Constants.ERRORNODATABOARPORT);
sucess = false;
}
return sucess;
}
// since serialBoardPort seems to be a globally declared variable
public SerialPort GetInstance()
{
return serialBoardPort;
}
// Let's name your class as board..
// on somewhere in your app code:
Board board = // GetValue
SerialPort boardSerialPort = board.GetInstance();
ClassXXX.StaticMethodNeedsPort(boardSerialPort); // pass your serial port to the static method
UPDATE: Since there was a bit of misunderstanding as the questioner said..
I suggest using an IoC container, read more here
Here is what I use. Normally this is already a part of frameworks such as MVVM Cross.
CODE:
public class Core
{
private static readonly Core instance = new Core();
private Dictionary<Type, object> container;
private Core()
{
container = new Dictionary<Type, object>();
}
public void RegisterSingleton<T>(T value) where T : class
{
Type type = typeof(T);
if (!container.ContainsKey(type))
container.Add(type, value);
}
public T GetSingleton<T>() where T : class
{
Type type = typeof(T);
if (container.ContainsKey(type))
return (T)container[type];
else
throw new Exception("Singleton instance not registered.");
}
public void RemoveSingleton<T>() where T : class
{
Type type = typeof(T);
if (container.ContainsKey(type))
container.Remove(type);
}
public void ClearSingletons()
{
container.Clear();
}
public static Core Instance
{
get { return instance; }
}
}
When your application loads add this line:
Core.Instance.ClearSingletons();
In case it already has a port upon loading since it is auto-generated by C# just register the instance too..
Core.Instance.RegisterSingleton(MySerialPortObject); // Or class. Can be object
On the part of the application when you need the port just get its instance like this...
SerialPort _myPort = Core.Instance.GetSingleton<X>(); // Where X value is the type of your registered object. If you are registering a SerialPort then replace X with SerialPort.
You can get the instance of your port anywhere you like. When I use this I normally register implementation of interfaces so that I can get it like
IFileHandler _fileHandler = Core.Instance.GetSingleton<IFileHandler>() // Where I registered the class that implements IFileHandler upon the startup of my application
Sorry for the long answer.

C# Writing to XML file does not save object

I have some experience in Java. Today I started programming in C# because I like Visual Studio.
As an exercise i'm building a system that manages all employees in a company.
Im working on a class called Function:
public class Function
{
private String functionname;
private String department;
private double hourpay;
public String getFunc()
{
return functionname;
}
public String getDepartement()
{
return department;
}
public double getPay()
{
return hourpay;
}
public String toString()
{
return ("Function: " + functionname + "\n" + "Department: " + department + "\n" + "Hourly Pay: " + hourpay);
}
public void setFunctionName(string functionname)
{
this.functionname = functionname;
}
public void setDepartment(String department)
{
this.department = department;
}
public void setPay(double pay)
{
this.hourpay = pay;
}
A very simple basic class to model a function, Now I would like to save functions in a XML file.
What I have in mind is:
After I created a function I put it in a list called Functions (List functions)
I write the list to an XML file.
If I want to update the XML file I simply load the List, add a new function, and then overwrite it to the XML file.
I made my class functions like this;
public class Functions{
public List<Function> functions = new List<Function>();
public void addFunction(Function func){
functions.Add(func);
}
public void writeFunctions()
{
System.Xml.Serialization.XmlSerializer writer =
new System.Xml.Serialization.XmlSerializer(typeof(Functions));
System.IO.StreamWriter file = new System.IO.StreamWriter(
#"C:\CDatabase\Functions.xml");
writer.Serialize(file, this);
file.Close();
}
}
To test it I implemented this in a click event of a button:
Function programmer = new Function();
schoonmaker.setFunctionName("Programmer");
schoonmaker.setDepartment("IT");
schoonmaker.setPay(16.50);
FunctionDatabase.addFunction(schoonmaker);
FunctionDatabase.writeFunctions();
It creates the XML file(If its not there), and this is in the XML file:
<Functions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<functions>
<Function />
</functions>
</Functions>
Its empty, and I dont understand why and how to fix it.
I think i'm thinking too easy, but I cant find a fix.
Thanks in advance,
Chris
C# doesn't use getter and setter methods like Java. Create your properties like this:
private string functionname;
public string functionname
{
get { return functionname; }
set { functionname = value; }
}
A suggestion would be to use properties instead of getter/setter functions - they are a feature of C# which are used a lot.
For example, instead of:
public double getPay()
{
return hourpay;
}
Try:
public double HourPay { get; set; }
Or if you want to be able to perform actions within the getter/setter:
private double hourPay;
public double HourPay
{
get
{
return hourPay;
}
set
{
hourPay = value;
}
}
By using public properties in this way, the XML serializer should generate the file you were expecting.

C# XmlSerialisation addin serialisation

I have written an Interface for writing a very very simple Plugin. In fact it is just a class that is loaded at runtime out of a dll file and is stored as Property in another class. That class that stores the interface has to get serialized. As example this is my serialized object:
<?xml version="1.0" encoding="utf-8"?><MD5HashMapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.net" />
But now If i want to load that Object I get an Exception:
As example :
{"<MD5HashMapper xmlns='http://www.vrz.net/Vrz.Map'> was not expected."}
So does anyone has an idea how to solve that problem?
Code:
I have an Interface named IMap that is shared in a dll file to create Addins based on that interface:
public interface IMap
{
object Map(object input);
}
I also have different Mappers (you can pass an input through them and they modify the output). All Mappers are derived from:
[XmlInclude(typeof(ConstMapper))]
[XmlInclude(typeof(FuncMapper))]
[XmlInclude(typeof(IdentMapper))]
[XmlInclude(typeof(NullMapper))]
[XmlInclude(typeof(RefMapper))]
[XmlInclude(typeof(VarMapper))]
[XmlInclude(typeof(TableMapper))]
[XmlInclude(typeof(AddinMapper))]
public class MapperBase:ComponentBase,IMap
{ public virtual object Map(object input) {
throw new NotImplementedException("Diese Methode muss überschrieben werden");
}
public override string ToString() {
return ShortDisplayName;
}
}
Just forget ComponentBase. It is not important for this...
Now i also have a AddinMapper. The main function of that mapper is to cast create MapperBase Object out of the IMap object:
And that is exactly that class I want to seralize including the properties of the Mapper Property (type IMap).
public class AddinMapper : MapperBase
{
private static MapperBase[] _mappers;
const string addinDirectory = #"Addin\Mappers\";
//Mappers from *.dll files are loaded here:
[XmlIgnore]
public static MapperBase[] Mappers
{
get
{
if (_mappers == null)
{
List<MapperBase> maps = new List<MapperBase>();
foreach (string dll in Directory.GetFiles(addinDirectory, "*.dll"))
{
if (Path.GetFileName(dll) != "IMap.dll")
{
var absolutePath = Path.Combine(Environment.CurrentDirectory, dll);
Assembly asm = Assembly.LoadFile(absolutePath);
foreach (Type type in asm.GetTypes().ToList().Where(p => p.GetInterface("IMap") != null))
{
maps.Add(new AddinMapper((IMap)Activator.CreateInstance(type)));
}
}
}
Mappers = maps.ToArray();
}
return _mappers;
}
set
{
_mappers = value;
}
}
IMap _base;
public string MapperString { get; set; }
[XmlIgnore()]
public IMap Mapper
{
get
{
if (_base == null)
{
Type type = null;
foreach (MapperBase mapperBase in Mappers)
{
if (mapperBase is AddinMapper && ((AddinMapper)mapperBase).Mapper.GetType().FullName == _mapperName)
{
type = (mapperBase as AddinMapper).Mapper.GetType();
break;
}
}
if (type != null)
{
XmlSerializer serializer = new XmlSerializer(type);
using (StringReader reader = new StringReader(MapperString))
{
Mapper = (IMap)serializer.Deserialize(reader);
}
}
}
return _base;
}
private set
{
_base = value;
StoreMapperString();
}
}
string _mapperName;
[System.ComponentModel.Browsable(false)]
public string MapperName
{
get
{
return _mapperName;
}
set
{
_mapperName = value;
}
}
public AddinMapper(IMap baseInterface) : this()
{
Mapper = baseInterface;
_mapperName = baseInterface.GetType().FullName;
}
public AddinMapper()
{
}
public override object Map(object input)
{
return Mapper.Map(input);
}
public override string ToString()
{
return Mapper.ToString();
}
private void StoreMapperString()
{
MemoryStream memstream = new MemoryStream();
XmlStore.SaveObject(memstream, Mapper);
using (StreamReader reader = new StreamReader(memstream))
{
memstream.Position = 0;
MapperString = reader.ReadToEnd();
}
}
}
An example for such a addin would be:
public class ReplaceMapper : IMap
{
public string StringToReplace { get; set; }
public string StringToInsert { get; set; }
public object Map(object input)
{
if (input is string)
{
input = (input as string).Replace(StringToReplace, StringToInsert);
}
return input;
}
}
And the Problem is I want to save the Settings like StringToReplace,... as xml
I ve solved my problem:
I really don t know why but take a look at this article: http://www.calvinirwin.net/2011/02/10/xmlserialization-deserialize-causes-xmlns-was-not-expected/
(if link is dead later)
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = elementName;
xRoot.IsNullable = true;
XmlSerializer ser = new XmlSerializer(typeof(MyObject), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader(xmlData));
MyObject tvd = (MyObject)ser.Deserialize(xRdr);
Now the important thing: It does not matter if you don t get an excption on serialization. You have to add the XmlRootAttribute on both ways: Serialisation and Deserialization.

HtmlAgilityPack XPath case ignoring

When I use
SelectSingleNode("//meta[#name='keywords']")
it doesn't work, but when I use the same case that used in original document it works good:
SelectSingleNode("//meta[#name='Keywords']")
So the question is how can I set case ignoring?
If the actual value is an unknown case, I think you have to use translate. I believe it's:
SelectSingleNode("//meta[translate(#name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='keywords']")
This is the hack, but it's the only option in XPath 1.0 (except the opposite to upper-case).
If you need a more comprehensive solution, you can write an extension function for the XPath processor which will perform a case insensitive comparison. It is quite a bit of code, but you only write it once.
After implementing the extension you can write your query as follows
"//meta[#name[Extensions:CaseInsensitiveComparison('Keywords')]]"
Where Extensions:CaseInsensitiveComparison is the extension function implemented in the sample below.
NOTE: this is not well tested I just threw it together for this response so the error handling etc. is non-existent!
The following is the code for the custom XSLT Context which provides one or more extension functions
using System;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml;
using HtmlAgilityPack;
public class XsltCustomContext : XsltContext
{
public const string NamespaceUri = "http://XsltCustomContext";
public XsltCustomContext()
{
}
public XsltCustomContext(NameTable nt)
: base(nt)
{
}
public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes)
{
// Check that the function prefix is for the correct namespace
if (this.LookupNamespace(prefix) == NamespaceUri)
{
// Lookup the function and return the appropriate IXsltContextFunction implementation
switch (name)
{
case "CaseInsensitiveComparison":
return CaseInsensitiveComparison.Instance;
}
}
return null;
}
public override IXsltContextVariable ResolveVariable(string prefix, string name)
{
return null;
}
public override int CompareDocument(string baseUri, string nextbaseUri)
{
return 0;
}
public override bool PreserveWhitespace(XPathNavigator node)
{
return false;
}
public override bool Whitespace
{
get { return true; }
}
// Class implementing the XSLT Function for Case Insensitive Comparison
class CaseInsensitiveComparison : IXsltContextFunction
{
private static XPathResultType[] _argTypes = new XPathResultType[] { XPathResultType.String };
private static CaseInsensitiveComparison _instance = new CaseInsensitiveComparison();
public static CaseInsensitiveComparison Instance
{
get { return _instance; }
}
#region IXsltContextFunction Members
public XPathResultType[] ArgTypes
{
get { return _argTypes; }
}
public int Maxargs
{
get { return 1; }
}
public int Minargs
{
get { return 1; }
}
public XPathResultType ReturnType
{
get { return XPathResultType.Boolean; }
}
public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator navigator)
{
// Perform the function of comparing the current element to the string argument
// NOTE: You should add some error checking here.
string text = args[0] as string;
return string.Equals(navigator.Value, text, StringComparison.InvariantCultureIgnoreCase);
}
#endregion
}
}
You can then use the above extension function in your XPath queries, here is an example for our case
class Program
{
static string html = "<html><meta name=\"keywords\" content=\"HTML, CSS, XML\" /></html>";
static void Main(string[] args)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
XPathNavigator nav = doc.CreateNavigator();
// Create the custom context and add the namespace to the context
XsltCustomContext ctx = new XsltCustomContext(new NameTable());
ctx.AddNamespace("Extensions", XsltCustomContext.NamespaceUri);
// Build the XPath query using the new function
XPathExpression xpath =
XPathExpression.Compile("//meta[#name[Extensions:CaseInsensitiveComparison('Keywords')]]");
// Set the context for the XPath expression to the custom context containing the
// extensions
xpath.SetContext(ctx);
var element = nav.SelectSingleNode(xpath);
// Now we have the element
}
}
This is how I do it:
HtmlNodeCollection MetaDescription = document.DocumentNode.SelectNodes("//meta[#name='description' or #name='Description' or #name='DESCRIPTION']");
string metaDescription = MetaDescription != null ? HttpUtility.HtmlDecode(MetaDescription.FirstOrDefault().Attributes["content"].Value) : string.Empty;
Alternatively use the new Linq syntax which should support case insensitive matching:
node = doc.DocumentNode.Descendants("meta")
.Where(meta => meta.Attributes["name"] != null)
.Where(meta => string.Equals(meta.Attributes["name"].Value, "keywords", StringComparison.OrdinalIgnoreCase))
.Single();
But you have to do an ugly null check for the attributes in order to prevent a NullReferenceException...

Categories