I have ClassLibrary (in visual studio 2010 C#) with a class Car:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Car")]
public class Car
{
public Car()
{
Name = "";
Parts = new List<string>();
}
public string Name { get; set; }
public List<string> Parts { get; set; }
}
But when I use it in vb6 project: there is no property "Parts":
http://i.imgur.com/x4h3BMp.jpg?1
What can I do to make property List<> visible?
Of course, the file "AssemblyInfo.cs" contains:
[assembly: ComVisible(true)]
P.S. I really do not want to create for each List the class, like this:
public class Parts
{
private List<string> _parts;
public Parts()
{
_parts = new List<string>();
}
public void Add(string part)
{
_parts.Add(part);
}
public string GetAt(int index)
{
if (0 <= index && index < _parts.Count)
return _parts[index];
return "";
}
public void Clear()
{
_parts.Clear();
}
public int Count{ get{ return _parts.Count; } }
}
because there are too many.
COM does not support generic collections; you'll have to use an array or ArrayList instead:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Car")]
public class Car
{
public Car()
{
Name = "";
Parts = new string[];
}
public string Name { get; set; }
public string[] Parts { get; set; }
}
If you want to use a List behind-the-scenes you could use a List<string> as a backing variable, then change the property accessors to translate the list to/from an array:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Car")]
public class Car
{
private List<string> _Parts;
public Car()
{
Name = "";
_Parts = new List<string>();
}
public string Name { get; set; }
public string[] Parts
{
get
{
return _Parts.ToArray();
}
set
{
_Parts = new List<string>(value);
}
}
}
I did not want to do so, but had:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Car")]
public class Car
{
public Car()
{
Name = "";
Parts = new Parts();
}
public string Name { get; set; }
public Parts Parts { get; set; }
}
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Parts")]
public class Parts : IList<string>
{
private List<string> _parts;
public Parts()
{
_parts = new List<string>();
}
#region IList<string> Members
public int IndexOf(string item)
{
return _parts.IndexOf(item);
}
public void Insert(int index, string item)
{
_parts.Insert(index, item);
}
public void RemoveAt(int index)
{
_parts.RemoveAt(index);
}
public string this[int index]
{
get
{
return _parts[index];
}
set
{
_parts[index] = value;
}
}
#endregion
#region ICollection<string> Members
public void Add(string item)
{
_parts.Add(item);
}
public void Clear()
{
_parts.Clear();
}
public bool Contains(string item)
{
return _parts.Contains(item);
}
public void CopyTo(string[] array, int arrayIndex)
{
_parts.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _parts.Count; }
}
public bool Remove(string item)
{
return _parts.Remove(item);
}
#endregion
#region ICollection<string> Members
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
#endregion
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
In vb6:
Option Explicit
Dim car As New ClassLibrary1.car
Dim parts As New ClassLibrary1.parts
Private Sub Form_Load()
parts.Add "wheel"
parts.Add "door"
parts.Add "hood"
parts.Add "trunk"
car.Name = "GAS-24"
Set car.parts = parts
car.parts.RemoveAt (0)
End Sub
Drawback of this approach is a lot of code:(
Let me know, if anyone knows something like this:
//**[MakeVisibleListInVB6]**
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("ClassLibrary1.Car")]
public class Car
{
public Car()
{
Name = "";
Parts = new Parts();
}
public string Name { get; set; }
public List<string> Parts { get; set; }
}
Related
I am new to C#. I'm trying to write a custom comparer which sorts a list of CityInfo object alphabetically by cityname.
public class CityInfoComparer
{
private readonly IComparer<string> _baseComparer;
public CityInfoComparer(IComparer<string> baseComparer)
{
_baseComparer = baseComparer;
}
public int Compare(CityInfo city1, CityInfo city2)
{
return _baseComparer.Compare(city1.CityName, city2.CityName);
}
}
public class CityList
{
public List<CityInfo> CityInfos { get; set; }
public void Sort(CityInfo city1, CityInfo city2)
{
CityInfos.Sort(new CityInfoComparer(StringComparer.CurrentCulture));
//CityInfos.Sort()
}
}
I am getting an error for this line:
CityInfos.Sort(new CityInfoComparer(StringComparer.CurrentCulture));
Cannot convert from CityInfo to Systems.Generic.Collections.Icomparer
You should inherit from IComparer, see below:
public class CityInfoComparer:IComparer<CityInfo>
{
private readonly IComparer<string> _baseComparer;
public CityInfoComparer(IComparer<string> baseComparer)
{
_baseComparer = baseComparer;
}
public int Compare(CityInfo city1, CityInfo city2)
{
return _baseComparer.Compare(city1.CityName, city2.CityName);
}
}
public class CityList
{
public List<CityInfo> CityInfos { get; set; }
public void Sort()
{
CityInfos.Sort( new CityInfoComparer(StringComparer.CurrentCulture));
}
}
I'm trying to inherit a method that returns a Generic BindingList of type ServerType. For example, let's say I have the following:
public interface IServer
{
string IpAddress { get; set; }
string Name { get; set; }
string HostName { get; set; }
string OsVersion { get; set; }
}
public class BaseServer : IServer
{
private string _IpAddress;
private string _Name;
private string _HostName;
private string _OsVersion;
public string IpAddress
{
get { return _IpAddress; }
set { _IpAddress = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string HostName
{
get { return _HostName; }
set { _HostName = value; }
}
public string OsVersion
{
get { return _OsVersion; }
set { _OsVersion = value; }
}
}
public class ServerTypeA : BaseServer { }
public class ServerTypeB : BaseServer { }
public class ServerTypeC : BaseServer { }
public class ServerTypeList : List<ServerTypeA>
{
public BindingList<ServerTypeA> ToBindingList()
{
BindingList<ServerTypeA> myBindingList = new BindingList<ServerTypeA>();
foreach (ServerTypeA item in this.ToList<ServerTypeA>())
{
_bl.Add(item);
}
return _bl;
}
}
Is there any way I can do the "ToBindingList" method without having to repeat it in each derived server class and have it use the correct generic type.
First offf donĀ“t derive from List<T>. Instead use it (favor composition over inheritance).
Then make your Repositories-class generic:
public class Repository : Server
{
}
public class Repositories<T> where T: Server
{
private List<T> theList = new List<T>();
public Repositories<T>(List<T> theList) this.theList = theList; }
public BindingList<T> ToBindingList()
{
BindingList<T> myBindingList = new BindingList<T>();
foreach (Titem in this.theList)
{
_bl.Add(item);
}
return _bl;
}
}
Now you can have Repositories-instances of arbitrary classes deriving from Server.
First, create a base list for all your collections:
public class MyListBase<T> : List<T>
where T: Server
{
public BindingList<T> ToBindingList()
{
BindingList<T> myBindingList = new BindingList<T>();
foreach (T item in this.ToList<T>())
myBindingList.Add(item);
return myBindingList;
}
}
Then use this one to inherit from:
public class Repositories : MyListBase<Repository>
{
}
I'm working on a project where I have some recursive data structure and I want to create a fixture for it.
The data structure is XmlCommandElement, it has a single method ToCommand that converts XmlCommandElement to Command.
Each node on the tree can be a XmlCommandElement and/or XmlCommandPropertyElement.
Now, in order to test the behaviour of the method ToCommand I want to fetch XmlCommandElement with some arbitrary data.
I want to control the depth of the tree and the amount of instances of XmlCommandElement and/or XmlCommandPropertyElement per node.
So here is the code I'm using for the fixture:
public class XmlCommandElementFixture : ICustomization
{
private static readonly Fixture _fixture = new Fixture();
private XmlCommandElement _xmlCommandElement;
public int MaxCommandsPerDepth { get; set; }
public int MaxDepth { get; set; }
public int MaxPropertiesPerCommand { get; set; }
public XmlCommandElementFixture BuildCommandTree()
{
_xmlCommandElement = new XmlCommandElement();
var tree = new Stack<XmlCommandElementNode>();
tree.Push(new XmlCommandElementNode(0, _xmlCommandElement));
while (tree.Count > 0) {
var node = tree.Pop();
node.Command.Key = CreateRandomString();
node.Command.Properties = CreateProperties();
if (MaxDepth > node.Depth) {
var commands = new List<XmlCommandElement>();
for (var i = 0; i < MaxCommandsPerDepth; i++) {
var command = new XmlCommandElement();
tree.Push(new XmlCommandElementNode(node.Depth + 1, command));
commands.Add(command);
}
node.Command.Commands = commands.ToArray();
}
}
return this;
}
public void Customize(IFixture fixture)
{
fixture.Customize<XmlCommandElement>(c => c.FromFactory(() => _xmlCommandElement)
.OmitAutoProperties());
}
private static string CreateRandomString()
{
return _fixture.Create<Generator<string>>().First();
}
private XmlCommandPropertyElement[] CreateProperties()
{
var properties = new List<XmlCommandPropertyElement>();
for (var i = 0; i < MaxPropertiesPerCommand; i++) {
properties.Add(new XmlCommandPropertyElement {
Key = CreateRandomString(),
Value = CreateRandomString()
});
}
return properties.ToArray();
}
private struct XmlCommandElementNode
{
public XmlCommandElementNode(int depth, XmlCommandElement xmlCommandElement)
{
Depth = depth;
Command = xmlCommandElement;
}
public XmlCommandElement Command { get; }
public int Depth { get; }
}
}
And this is how I'm using it:
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
This works perfectly fine! but the issue I have with it is it isn't generic, the whole point of AutoFixture at least as far as I know is to avoid making specific fixtures.
So what I would really like to do is something like this (found it here but it doesn't work for me.):
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandElement), 3));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandPropertyElement), 4));
xmlCommandElement = fixture.Create<XmlCommandElement>();
Here is all the code for reference:
Interfaces:
public interface ICommandCollection : IEnumerable<ICommand>
{
ICommand this[string commandName] { get; }
void Add(ICommand command);
}
public interface ICommandPropertyCollection : IEnumerable<ICommandProperty>
{
string this[string key] { get; }
void Add(ICommandProperty property);
}
public interface ICommandProperty
{
string Key { get; }
string Value { get; }
}
public interface ICommand
{
ICommandCollection Children { get; set; }
string Key { get; }
ICommandPropertyCollection Properties { get; }
}
public interface ICommandConvertible
{
ICommand ToCommand();
}
Classes:
public sealed class CommandPropertyCollection : ICommandPropertyCollection
{
private readonly IDictionary<string, ICommandProperty> _properties;
public CommandPropertyCollection()
{
_properties = new ConcurrentDictionary<string, ICommandProperty>();
}
public string this[string key]
{
get
{
ICommandProperty property = null;
_properties.TryGetValue(key, out property);
return property.Value;
}
}
public void Add(ICommandProperty property)
{
_properties.Add(property.Key, property);
}
public IEnumerator<ICommandProperty> GetEnumerator()
{
return _properties.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class CommandProperty : ICommandProperty
{
public CommandProperty(string key, string value)
{
Key = key;
Value = value;
}
public string Key { get; }
public string Value { get; }
}
public sealed class Command : ICommand
{
public Command(string key, ICommandPropertyCollection properties)
{
Key = key;
Properties = properties;
}
public ICommandCollection Children { get; set; }
public string Key { get; }
public ICommandPropertyCollection Properties { get; }
}
public class XmlCommandPropertyElement : ICommandPropertyConvertible
{
[XmlAttribute("key")]
public string Key { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
public ICommandProperty ToCommandProperty()
{
return new CommandProperty(Key, Value);
}
}
Finally, the class I'm trying to test is as follow:
public class XmlCommandElement : ICommandConvertible
{
[XmlArray]
[XmlArrayItem("Command", typeof(XmlCommandElement))]
public XmlCommandElement[] Commands { get; set; }
[XmlAttribute("key")]
public string Key { get; set; }
[XmlArray]
[XmlArrayItem("Property", typeof(XmlCommandPropertyElement))]
public XmlCommandPropertyElement[] Properties { get; set; }
public ICommand ToCommand()
{
ICommandPropertyCollection properties = new CommandPropertyCollection();
foreach (var property in Properties) {
properties.Add(property.ToCommandProperty());
}
ICommand command = new Command(Key, properties);
return command;
}
}
The test itself looks like this:
namespace Yalla.Tests.Commands
{
using Fixtures;
using FluentAssertions;
using Ploeh.AutoFixture;
using Xbehave;
using Yalla.Commands;
using Yalla.Commands.Xml;
public class XmlCommandElementTests
{
[Scenario]
public void ConvertToCommand(XmlCommandElement xmlCommandElement, ICommand command)
{
$"Given an {nameof(XmlCommandElement)}"
.x(() =>
{
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
});
$"When the object is converted into {nameof(ICommand)}"
.x(() => command = xmlCommandElement.ToCommand());
"Then we need to have a root object with a key"
.x(() => command.Key.Should().NotBeNullOrEmpty());
"And 4 properties as its children"
.x(() => command.Properties.Should().HaveCount(4));
}
}
}
Thanks to Mark Seemann! the final solution looks like this:
public class RecursiveCustomization : ICustomization
{
public int MaxDepth { get; set; }
public int MaxElements { get; set; }
public void Customize(IFixture fixture)
{
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(MaxDepth));
fixture.RepeatCount = MaxElements;
}
}
And can be used like this:
xmlCommandElement = new Fixture().Customize(new RecursiveCustomization {
MaxDepth = 2,
MaxElements = 3
}).Create<XmlCommandElement>();
You can fairly easily create a small tree by changing the Fixture's recursion behaviour:
[Fact]
public void CreateSmallTree()
{
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(recursionDepth: 2));
var xce = fixture.Create<XmlCommandElement>();
Assert.NotEmpty(xce.Commands);
}
The above test passes.
I want to serialize a list of XmlAttribute's in a XmlElement.
Some general info about the program:
It's a program where you can add product's with some attributes like the name, a description, and some properties (height, width, brand, condition), but the user can choose how many he want to add (not a fixed number).
Here is the class diagramm of the program:
Here is the code of the ManagerRoot class:
[Serializable]
public class ManagerRoot
{
[XmlElement("ProductRoot")]
public ProductRoot ProductRoot = new ProductRoot();
}
Here is the code of the ProductRoot Class:
[Serializable]
public class ProductRoot
{
[XmlElement("Product")]
public List<Product> ProductList { get; set; }
private void addProduct()
{
//?
}
}
Here is the code of the Product class:
[Serializable]
public class Product
{
[XmlIgnore]
private string _header;
[XmlAttribute("Header")]
public string Header
{
get { return this._header; }
set { this._header = value; }
}
[XmlIgnore]
private string _description;
[XmlAttribute("Description")]
public string Description
{
get { return this._description; }
set { this._description = value; }
}
[XmlIgnore]
private string _link;
[XmlAttribute("Link")]
public string Link
{
get { return this._link; }
set { this._link = value; }
}
[XmlIgnore]
private List<string> _properties;
[XmlAttribute("Properties")]
public List<string> Properties
{
get
{
}
set
{
}
}
}
Now I don't know what i have to do with the getter and setter of the list inside the class. And how can I add a new product with a name, description, link & a filled properties list?
For collections you need to annotate the property with XmlArray and XmlArrayItem to define which is the contained item. Please follow the same ProductList pattern for all collection based properties.
namespace ConsoleApplication1
{
[Serializable]
public class ProductRoot
{
[XmlArray]
[XmlArrayItem(ElementName = "Product", Type = typeof(Product))]
public List<Product> ProductList { get; set; }
}
[Serializable]
public class Product
{
[XmlIgnore]
private string _header;
[XmlAttribute("Header")]
public string Header {
get { return this._header; }
set { this._header = value; }
}
[XmlIgnore]
private string _description;
[XmlAttribute("Description")]
public string Description {
get { return this._description; }
set { this._description = value; }
}
[XmlIgnore]
private string _link;
[XmlAttribute("Link")]
public string Link {
get { return this._link; }
set { this._link = value; }
}
[XmlIgnore]
private List<string> _properties;
[XmlAttribute("Properties")]
public List<string> Properties { get; set; }
}
static class Program
{
static void Main() {
var productRoot = new ProductRoot();
var products = new List<Product>();
products.Add(new Product() { Description = "A", Properties = new List<string> { "PropA" } });
products.Add(new Product() { Description = "B", Properties = new List<string> { "PropB" } });
productRoot.ProductList = products;
Test(productRoot);
}
static void Test<T>(T obj) {
using (MemoryStream stream = new MemoryStream()) {
XmlSerializer s = new XmlSerializer(typeof(T));
using (var stringWriter = new StringWriter()) {
using (var writer = XmlWriter.Create(stringWriter)) {
s.Serialize(stringWriter, obj);
}
Console.WriteLine(stringWriter.ToString());
}
}
}
}
Imagine a class as follows.. It's a class provided to me to work with.. I cannot change its source..
public class MyClass
{
object _Object { get; set; }
public void FuncA1() { _Object = new object(); }
public void FuncA2() { _Object = new List<object>(); }
public int FuncB1() { _Object = 0; return 0; }
public int FuncB2() { _Object = 123; return 123; }
public string FuncC1() { _Object = null; return null; }
public string FuncC2() { _Object = "Hello"; return "Hello"; }
}
Im trying to create a wrapper for this class, such that I can group its many functions into categories..
MyWrapper.Voids.FuncA1();
MyWrapper.Voids.FuncA2();
MyWrapper.Integers.FuncB1();
MyWrapper.Integers.FuncB2();
MyWrapper.Strings.FuncC1();
MyWrapper.Strings.FuncC2();
The only solution I can think of for this scenario is to design the wrapper like this:
public class MyWrapper
{
MyClass _Instance { get; set; }
public _Void Voids { get; private set; }
public _Integer Integers { get; private set; }
public _String Strings { get; private set; }
public class _Void
{
MyWrapper _Parent { get; set; }
public void FuncA1() { _Parent._Instance.FuncA1(); }
public int FuncA2() { return _Parent._Instance.FuncA2(); }
}
public class _Integer
{
...
}
public class _String
{
...
}
public MyWrapper()
{
_Instance = new MyClass();
Voids = new _Voids(this);
Integers = new _Integer(this);
Strings = new _String(this);
}
}
This solution works, but has a number of problems:
- The inner classes are forced to be public, which allows them to be instantiated by the user..
- I am forced to maintain a reference of the parent object in the child classes..
Is there a better way of doing this?
EDIT: The code posted initially was a bit confusing, in the sense that it was diverting attention away from the core issue and more into the issues of whether a function would cause exceptions or not if they all work on the same object..
NOTE: This is not actual code.. I hacked together this example to show what I'm trying to do.. CREATE A WRAPPER AROUND AN OBJECT (I cannot change the original object's code) AND GROUP FUNCTIONS INTO CATEGORIES..
FINAL EDIT: following suggestion by Juharr.. here's what ive done to accomplish what i wanted.. for the betterment of others..
public interface IVoid
{
void FuncA1();
void FuncA2();
}
public interface IInteger
{
int FuncB1();
int FuncB2();
}
public class MyWrapper
{
public MyClass Instance { get; private set; }
public IVoid Voids { get; private set; }
public IInteger Integers { get; private set; }
private abstract class MyBase
{
protected MyWrapper Parent { get; set; }
protected MyClass Instance { get { return Parent.Instance; } }
public MyBase(MyWrapper oParent) { Parent = oParent; }
}
private class MyVoid : MyBase, IVoid
{
public MyVoids (MyWrapper oParent) : base(oParent) { }
public void FuncA1() { Instance.FuncA1(); }
public void FuncA2() { Instance.FuncA2(); }
}
private class MyInteger : MyBase, IInteger
{
public MyInteger (MyWrapper oParent) : base(oParent) { }
public int FuncB1() { return Instance.FuncB1(); }
public int FuncB2() { return Instance.FuncB2(); }
}
public MyWrapper()
{
Instance = new MyClass();
Voids = new MyVoid(this);
Integers = new MyInteger(this);
}
}
You could write public interfaces instead. Then your inner classes don't have to be public. So something like this.
public interface IIntger
{
void Set(int iValue);
int Get();
}
public class MyWrapper
{
MyClass _Instance { get; set; }
public IInteger Integer { get; private set; }
private class _Integer : IInteger
{
MyWrapper _Parent { get; set; }
public void Set(int iValue) { _Parent._Instance.IntegerSet(iValue); }
public int Get() { return _Parent._Instance.IntegerGet(); }
}
public MyWrapper()
{
_Instance = new MyClass();
Integer = new _Integer(this);
}
}
EDIT:
To answer the second part of your question you will either need the reference to the parent class or a reference to the class you are wrapping. So you could have this instead.
public class MyWrapper
{
public IInteger Integer { get; private set; }
private class _Integer : IInteger
{
MyClass _Instance { get; set; }
public _Integer(MyClass myClass) { _Instance = myClass; }
public void Set(int iValue) { _Instance.IntegerSet(iValue); }
public int Get() { return _Instance.IntegerGet(); }
}
public MyWrapper(MyClass instance)
{
Integer = new _Integer(instance);
}
}