C# Mongo BsonDocumentBackedClass not working for embedded POCO class - c#

I have a two C# POCO's setup as BsonDocumentBackedClass. Individually they work as expected, if I make one a property of another the property class no longer works and I cannot set any values in it. Here is an example:
[Serializable, DataContract, BsonSerializer(typeof(VehicleStatusClassSerializer))]
public class VehicleStatus : BsonParent, IVehicleStatus
{
public VehicleStatus() : this(new BsonDocument()) { }
internal VehicleStatus(BsonDocument backingDocument) : base(backingDocument, new VehicleStatusClassSerializer()) { }
[DataMember, BsonElement]
public String IntelliStatus
{
get { return GetValue("IntelliStatus", default(String)); }
set { SetValue("IntelliStatus", value); }
}
[DataMember, BsonElement]
public String Description
{
get { return GetValue("Description", default(String)); }
set { SetValue("Description", value); }
}
[DataMember, BsonElement, BsonSerializer(typeof(GeoLocationVehicleInfoClassSerializer))]
public GeoLocationVehicleInfo VehicleInfo
{
get { return GetValue<GeoLocationVehicleInfo>("VehicleInfo", null); }
set { SetValue("VehicleInfo", value); }
}
The serializer looks like this
public class VehicleStatusClassSerializer : BsonDocumentBackedClassSerializer<VehicleStatus>
{
public VehicleStatusClassSerializer()
{
RegisterMember("IntelliStatus", "IntelliStatus", new StringSerializer());
RegisterMember("Description", "Description", new StringSerializer());
RegisterMember("VehicleInfo", "VehicleInfo", new GeoLocationVehicleInfoClassSerializer());
}
protected override VehicleStatus CreateInstance(BsonDocument backingDocument)
{
return new VehicleStatus(backingDocument);
}
}
The embedded class looks like this
[Serializable, DataContract, BsonSerializer(typeof(GeoLocationVehicleInfoClassSerializer))]
public class GeoLocationVehicleInfo : BsonDocumentBackedClass//, IGeoLocationVehicleInfo
{
public GeoLocationVehicleInfo() : this(new BsonDocument()) { }
internal GeoLocationVehicleInfo(BsonDocument backingDocument) : base(backingDocument, new GeoLocationClassSerializer())
{
}
[DataMember, BsonElement]
public Double speed {
get
{
try
{
return GetValue<Double>("speed", 0.0);
}
catch (Exception)
{
return 0.0;
}
}
set { SetValue("speed", value); }
}
}
And here is the embedded documents serializer
public class GeoLocationVehicleInfoClassSerializer : BsonDocumentBackedClassSerializer<GeoLocationVehicleInfo>
{
public GeoLocationVehicleInfoClassSerializer()
{
RegisterMember("speed", "speed", new BsonDoubleSerializer());
}
protected override GeoLocationVehicleInfo CreateInstance(BsonDocument backingDocument)
{
return new GeoLocationVehicleInfo(backingDocument);
}
}
So in the C# code if I try and do VehicleStatus.VehicleInfo.speed = 1.0. It never gets set.

Related

Generic Class Polymorphisim

If I have the following:
public abstract class Parameter<T>
{
protected T value;
public virtual T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue){}
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return value; }
set { this.value = value > 100 ? 100 : value; }
}
public IntParameter(int startingValue) : base (startingValue) {}
}
Is there any way to create some List<Parameter> that can contain any of the derived types? For example, something like:
// no type specified in Parameter
List<Parameter> storedParameters = new List<Parameter>();
storedParameters.Add(new FloatParameter(2f));
storedParameters.Add(new IntParameter(7));
foreach(Parameter p in storedParameters)
{
DoSomethingWithValue(p.Value);
}
Or, alternatively, if this implementation is flawed, is there a better way to do this? What I have here feels slightly naive.
The only way I see to manage such case is to have and Interface that you use to manage the generic types, something like this should work:
public interface IParameter
{
void DoSomething();
}
public abstract class Parameter<T>
{
protected T value;
public T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>, IParameter
{
public FloatParameter(float startingValue) : base(startingValue) { }
public void DoSomething()
{
Console.WriteLine(value);
}
}
public class IntParameter : Parameter<int>, IParameter
{
public IntParameter(int startingValue) : base(startingValue) { }
public void DoSomething()
{
Console.WriteLine(value);
}
}
Ont his case you would be able to create a List of the Interface IParameter and add there specific instances:
var list = new List<IParameter>();
list.Add(new FloatParameter(1F));
list.Add(new IntParameter(1));
foreach (var item in list)
{
item.DoSomething();
}
Try to add nongeneric interface. Here is an example:
public class Program
{
static void Main(string[] args)
{
try
{
List<IParameter> storedParameters = new List<IParameter>();
storedParameters.Add(new FloatParameter(2f));
storedParameters.Add(new IntParameter(7));
foreach (IParameter p in storedParameters)
{
Console.WriteLine(p.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public interface IParameter
{
object value { get; }
}
public class Parameter<T> : IParameter
{
public object value { get; protected set; }
public virtual T Value
{
get { return (T)value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue){ }
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return (int)value; }
set { this.value = value > 100 ? 100 : value; }
}
public IntParameter(int startingValue) : base (startingValue) { }
}
No, it's not possible to do it.
What you are trying to do is to have an interface (or base class) that expose a property of an undefined type, to be able to then retrieve that value and dispatch it dynamically to the proper override of DoSomethingWithValue.
What you are after is achievable defining the property as dynamic, instead of using generics.
public class Parameter
{
protected dynamic value;
public dynamic Value
{
get { return value; }
set { this.value = value; }
}
public Parameter(dynamic startingValue)
{
value = startingValue;
}
}
public class MyStuff {
public void DoStuff()
{
List<Parameter> storedParameters = new List<Parameter>();
storedParameters.Add(new Parameter(2f));
storedParameters.Add(new Parameter(7));
foreach (Parameter p in storedParameters)
{
DoSomethingWithValue(p.Value);
}
}
}
Otherwise you should look into implementing a Double dispatch.
You can do it by defining a common interface and using the visitor pattern.
public interface IParameterVisitor
{
void VisitInt(int value);
void VisitFloat(float value);
}
public interface IParameter
{
void Accept(IParameterVisitor visitor);
}
The previous implementation has to be modified a bit:
public abstract class Parameter<T> : IParameter
{
protected T value;
public virtual T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
public abstract void Accept(IParameterVisitor visitor);
}
FloatParameter will VisitFloat, and IntParameter will VisitInt
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue) { }
public override void Accept(IParameterVisitor visitor)
{
visitor.VisitFloat(this.value);
}
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return value; }
set { this.value = value > 100 ? 100 : value; }
}
public override void Accept(IParameterVisitor visitor)
{
visitor.VisitInt(this.value);
}
public IntParameter(int startingValue) : base(startingValue) { }
}
And our visitor for example:
public class MyVisitor : IParameterVisitor
{
public void VisitInt(int value)
{
Console.WriteLine($"Visiting an int: {value}");
}
public void VisitFloat(float value)
{
Console.WriteLine($"Visiting a float: {value}");
}
}
Finally, the usage:
var parameters =
new List<IParameter> {new FloatParameter(0.5f), new IntParameter(1)};
var visitor = new MyVisitor();
foreach (IParameter parameter in parameters) {
parameter.Accept(visitor);
}
If you change the value to an object you will be able to set the value to whatever type you like:
class Program
{
static void Main(string[] args)
{
// no type specified in Parameter
var storedParameters = new List<ParameterBase>();
storedParameters.Add(new FloatParameter(3.5F));
storedParameters.Add(new IntParameter(7));
foreach (var p in storedParameters)
{
Console.WriteLine(p.Value);
}
}
}
public class ParameterBase
{
protected object value;
public virtual object Value
{
get { return value; }
set { this.value = value; }
}
}
public class FloatParameter : ParameterBase
{
public FloatParameter(float value)
{
Value = value;
}
}
public class IntParameter : ParameterBase
{
public IntParameter(int value)
{
Value = value;
}
}
UPDATED: Use object instead of dynamic and removed ValueType as suggested by #Pieter Witvoet

xml serialization with conditions

I have the following classes in a serialization:
[XmlRoot()]
public class XmlExample
{
private NodeA_Elem _nodea;
[XmlElemnt("NodeA")]
public NodeA_Elem NodeA
{
get
{
return _nodea;
}
set
{
_nodea=value;
}
}
private NodeB_Elem _nodeb;
[XmlElemnt("NodeB")]
public NodeB_Elem NodeB
{
get
{
return _nodeb;
}
set
{
_nodeb=value;
}
}
private NodeC_Elem _nodec;
[XmlElemnt("NodeC")]
public NodeC_Elem NodeC
{
get
{
return _nodec;
}
set
{
_nodec=value;
}
}
public class NodeA_Elem
{
[XmlText()]
public string value{get;set;}
}
public class NodeB_Elem
{
[XmlText()]
public string value{get;set;}
}
public class NodeC_Elem
{
[XmlText()]
public string value{get;set;}
}
If the value property of any classes NodaA, NodeB or NodeC is null or empty I have the following result:
<XmlExample>
<NodeA/>
<NodeB/>
<NodeC/>
</XmlExample>
What I have to do to these nodes don't appear like empty nodes if I don't set the value property?
You can use ShouldSerialize* pattern, something like this:-
public bool ShouldSerializeNodeA() {
return NodeA != null;
}
Refer here :-
Conditional xml serialization
Update:
Make it non nullable:-
[XmlElement(IsNullable = false)]
Edit:
Earlier I mentioned :-
public bool ShouldSerializeNodeA() {
return NodeB != null;
}
My mistake, it should be like this:-
public bool ShouldSerializeNodeA() {
return NodeA != null;
}
You can also use a boolean property with the suffix xSpecified to indicate whether or not to serialize a property. This is used by Xml clients which consume xml which have a default value (e.g. as specified with default=xxx in an XSD):
public bool NodeASpecified
{
get { return _nodea != null && !String.IsNullOrEmpty(_nodea.value); }
}
Do not mark these Specified properties with any Xml attributes.
Not related, but hard coding the *Specified properties to true in a partial class is useful if you have consumed a web service which has a default and a minOccurs=0, which would otherwise not be sent at all to the service if the value was coincidentally the same as the default value.
I added up some comments and find a solution. I could use the ShouldSerialize pattern in my code. The resulting code is:
[XmlRoot()]
public class XmlExample
{
private NodeA_Elem _nodea;
[XmlElemnt("NodeA")]
public NodeA_Elem NodeA
{
get
{
return _nodea;
}
set
{
_nodea=value;
}
}
public bool ShouldSerializeNodeA()
{
return !String.IsNullOrEmpty(_nodea.value);
}
private NodeB_Elem _nodeb;
[XmlElemnt("NodeB")]
public NodeB_Elem NodeB
{
get
{
return _nodeb;
}
set
{
_nodeb=value;
}
}
public bool ShouldSerializeNodeB()
{
return !String.IsNullOrEmpty(_nodeb.value);
}
private NodeC_Elem _nodec;
[XmlElemnt("NodeC")]
public NodeC_Elem NodeC
{
get
{
return _nodec;
}
set
{
_nodec=value;
}
}
public bool ShouldSerializeNodeC()
{
return !String.IsNullOrEmpty(_nodec.value);
}
}
public class NodeA_Elem
{
[XmlText()]
public string value{get;set;}
}
public class NodeB_Elem
{
[XmlText()]
public string value{get;set;}
}
public class NodeC_Elem
{
[XmlText()]
public string value{get;set;}
}
Edit:
Here is the full code of my example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Serialization_Example
{
class Program
{
static void Main(string[] args)
{
MyXmlDocument document = new MyXmlDocument();
document.MyExample.NodeA.value = "Value To Node A";
document.MyExample.NodeC.value = "Value To Node C";
document.WriteToXml(#"C:\Users\user_Name\Desktop\mydocument.xml");
}
}
[XmlRoot("xmlExample")]
public class XmlExample
{
private NodeA_Elem _nodea;
[XmlElement()]
public NodeA_Elem NodeA
{
get
{
return _nodea;
}
set
{
_nodea = value;
}
}
public bool ShouldSerializeNodeA()
{
return !String.IsNullOrEmpty(_nodea.value);
}
private NodeB_Elem _nodeb;
[XmlElement("NodeB")]
public NodeB_Elem NodeB
{
get
{
return _nodeb;
}
set
{
_nodeb = value;
}
}
public bool ShouldSerializeNodeB()
{
return !String.IsNullOrEmpty(_nodeb.value);
}
private NodeC_Elem _nodec;
[XmlElement("NodeC")]
public NodeC_Elem NodeC
{
get
{
return _nodec;
}
set
{
_nodec = value;
}
}
public bool ShouldSerializeNodeC()
{
return !String.IsNullOrEmpty(_nodec.value);
}
public XmlExample()
{
_nodea = new NodeA_Elem();
_nodeb = new NodeB_Elem();
_nodec = new NodeC_Elem();
}
}
public class NodeA_Elem
{
[XmlText()]
public string value { get; set; }
}
public class NodeB_Elem
{
[XmlText()]
public string value { get; set; }
}
public class NodeC_Elem
{
[XmlText()]
public string value { get; set; }
}
public class MyXmlDocument
{
private XmlExample _myexample;
public XmlExample MyExample
{
get
{
return _myexample;
}
set
{
_myexample = value;
}
}
public void WriteToXml(string path)
{
XmlSerializer serializer = new XmlSerializer(typeof(XmlExample));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.Unicode;
StringWriter txtwriter = new StringWriter();
XmlWriter xmlwtr = XmlWriter.Create(txtwriter, settings);
serializer.Serialize(xmlwtr, MyExample);
StreamWriter writer = new StreamWriter(path);
writer.Write(txtwriter.ToString());
writer.Close();
}
public MyXmlDocument()
{
_myexample = new XmlExample();
}
}
}
If you compile it, you'll see that if I don't set the value for NodeB.value, it won't generate a empty node like was happening before.

How to set a property in class from a derived class

I am not sure how this functions in C#.
I have a class:
public class FindIt()
{
}
public class FindItFrm()
{
private bool _amISet = false;
public FindItFrm()
{
}
public bool AmISet()
{
get { return _amISet; }
set { _amISet = value; }
}
}
And the class that I am working in has:
public class MyHelper() : FindIt
{
// Constructor
public MyHelper()
: base(new FindItFrm())
}
I want to set a property (AmISet) in the FindItFrm while inside the MyHelper class. How would I accomplish this?
Your code should look like this (in the future, please post working code for examples):
public class FindIt
{
// You need to let your derived class access the FindItFrm
protected FindItFrm Frm;
// Constructor needs to accept a FindItFrm
public FindIt(FindItFrm frm)
{
Frm = frm;
}
}
public class FindItFrm
{
private bool _amISet = false;
public bool AmISet
{
get { return _amISet; }
set { _amISet = value; }
}
}
public class MyHelper : FindIt
{
// Constructor
public MyHelper()
: base(new FindItFrm())
{
Frm.AmISet = true;
}
}

Extensible .NET Configuration

I would like to distribute a DLL with a ConfigurationSection as follows:
public class StandardConfiguration : ConfigurationSection
{
public static StandardConfiguration GetInstance()
{
return (StandardConfiguration)ConfigurationManager.GetSection("customConfigSection");
}
[ConfigurationProperty("childConfig")]
public StandardChildConfig ChildConfig
{
get { return (StandardChildConfig)this["childConfig"]; }
set { this["childConfig"] = value; }
}
}
public class StandardChildConfig : ConfigurationElement
{
[ConfigurationProperty("p1")]
public string P1
{
get { return (string)this["p1"]; }
set { this["p1"] = value; }
}
}
I would like to make the ConfigurationSection and its child ConfigElement inheritable. This can be done using a type parameter as follows:
public class StandardConfiguration<TChildConfig> : ConfigurationSection
where TChildConfig : StandardChildConfig
{
[ConfigurationProperty("childConfig")]
public TChildConfig ChildConfig
{
get { return (TChildConfig)this["childConfig"]; }
set { this["childConfig"] = value; }
}
}
public class StandardChildConfig : ConfigurationElement
{
[ConfigurationProperty("p1")]
public string P1
{
get { return (string)this["p1"]; }
set { this["p1"] = value; }
}
}
However, I think this would prevent me from having a static Instance to reference from other classes in my DLL because I would not know the ultimate type of child ConfigurationElement.
Any ideas or suggestions on how to implement this more cleanly are welcome.
Thanks.
EDIT
Assuming that there is a <customConfigSection> in the application's configuration, I can use StandardConfiguration.GetInstance().ChildConfig.P1 to access the P1 value in the first scenario. How would I access that same value in the second scenario? How would I implement GetInstance()?
EDIT 2
Below is the "zero-coding" scenario:
<?xml version="1.0"?>
<configuration>
<configSections>
<section
name="customConfig"
type="WebsiteTemplate.Config.StandardConfigruation, WebsiteTemplate"
/>
</configSections>
<customConfig baseProp1="a">
<childConfig baseProp2="b" />
</customConfig>
</configuration>
And here is the scenario where the configuration was extended:
<?xml version="1.0"?>
<configuration>
<configSections>
<section
name="customConfig"
type="WebsiteTemplate.Extended.Config.ExtendedConfigruation, WebsiteTemplate.Extended"
/>
</configSections>
<customConfig baseProp1="a" extendedProp1="c">
<childConfig baseProp2="b" extendedProp2="d" />
</customConfig>
</configuration>
In the second instance StandardConfiguration.GetInstance() doesn't make any sense because StandardConfiguraiton is generic. You'd have to use StandardConfiguration<MyChildConfig>.GetInstance().ChildConfig.P1
You might be able to do something like this:
public class StandardConfigurationBase : ConfigurationSection
{
public static StandardConfigurationBase GetInstance()
{
return (StandardConfigurationBase) ConfigurationManager.GetSection("customConfigSection");
}
[ConfigurationProperty("childConfig")]
public StandardChildConfig ChildConfig
{
get { return (StandardChildConfig) this["childConfig"]; }
set { this["childConfig"] = value; }
}
}
public class StandardConfiguration<TChildConfig> : StandardConfigurationBase
where TChildConfig : StandardChildConfig
{
[ConfigurationProperty("childConfig")]
public new TChildConfig ChildConfig
{
get { return (TChildConfig)this["childConfig"]; }
set { this["childConfig"] = value; }
}
}
public class StandardChildConfig : ConfigurationElement
{
[ConfigurationProperty("p1")]
public string P1
{
get { return (string)this["p1"]; }
set { this["p1"] = value; }
}
}
Then access the child when its specific type is not known:
StandardConfigurationBase b = new StandardConfiguration<StandardChildConfig>();
StandardChildConfig x = StandardConfigurationBase.GetInstance().ChildConfig;
But, I'm unclear of the real value in doing this.
The "answer" to my question is to break the base config up into an abstract class with type parameters and an interface.
Below shows what is defined in the BaseLib.dll. There is a default configuration and default child configuration.
Interface and absract class
public interface IAppConfig
{
string AppProp1 { get; }
SubConfig SubConfig { get; }
}
public abstract class BaseAppConfig<TSubConfig> : ConfigurationSection, IAppConfig
where TSubConfig : SubConfig
{
[ConfigurationProperty("appProp1")]
public string AppProp1
{
get { return (string)this["appProp1"]; }
set { this["appProp1"] = value; }
}
[ConfigurationProperty("subConfig")]
public TSubConfig SubConfig
{
get { return (TSubConfig)this["subConfig"]; }
set { this["subConfig"] = value; }
}
// Implement the interface
string IAppConfig.AppProp1 { get { return this.AppProp1; } }
SubConfig IAppConfig.SubConfig { get { return this.SubConfig; } }
}
Default implementations
public class AppConfig : BaseAppConfig<SubConfig>
{
const string SECTION_KEY = "AppConfig";
public static IAppConfig Instance
{
get { return (IAppConfig)ConfigurationManager.GetSection(SECTION_KEY); }
}
}
public class SubConfig : ConfigurationElement
{
[ConfigurationProperty("supProp1")]
public string SubProp1
{
get { return (string)this["supProp1"]; }
set { this["supProp1"] = value; }
}
}
How the config is accessed from BaseLib.dll
public class ArbitraryClass
{
void DoSometing()
{
Console.Write(AppConfig.Instance.SubConfig.SubProp1);
}
}
Below shows what is defined in the ExtLib.dll. Both the configuration and child configuration are extended.
Extended implementations
public class ExtAppConfig : BaseAppConfig<ExtSubConfig>
{
public static ExtAppConfig Instance
{
get { return (ExtAppConfig)AppConfig.Instance; }
}
[ConfigurationProperty("extAppProp1")]
public string ExtAppProp1
{
get { return (string)this["extAppProp1"]; }
set { this["extAppProp1"] = value; }
}
}
public class ExtSubConfig : SubConfig
{
[ConfigurationProperty("extSubProp1")]
public string ExtSubProp1
{
get { return (string)this["extSubProp1"]; }
set { this["extSubProp1"] = value; }
}
}
How the config is accessed from ExtLib.dll
public class ExtArbitraryClass
{
void DoSometing()
{
Console.Write(ExtAppConfig.Instance.SubConfig.ExtSubProp1);
}
}
There is a little more defined in the library, but it should make extending this configuration relatively easy.

generic interfaces and polymorphism

I have following code:
public abstract class Operand<T>
{
public T Value { get; protected set; }
public bool IsEmpty { get; protected set; }
public override string ToString()
{
return IsEmpty ? Value.ToString() : string.Empty;
}
}
public class DoubleOperand : Operand<Double> {}
public interface IOperandFactory<T>
{
Operand<T> CreateEmptyOperand();
Operand<T> CreateOperand(T value);
}
public class DoubleFactory: IOperandFactory<double>
{
public Operand<Double> CreateEmptyOperand()
{
//implementation
}
public Operand<Double> CreateOperand(double value)
{
//implementation
}
}
I simlified code to just show the structure.
Now I need associationDictionary that will return IOperandFactory for required Type:
Something like this:
var factoryDict =
new Dictionary<Type, IOperandFactory<>>() { { typeof(double), new DoubleFactory() } };
Could you help me to achieve it if it is possible?
To do that, you would need to have a non-generic interface (typically in addition to the generic interface), i.e. a non-generic Operand, with Operand<T> : Operand (could also be an interface), and a non-generic IOperandFactory with IOperandFactory<T> : IOperandFactory. The only other option is to store a Dictionary<Type, object>, and have the caller cast as necessary.
Here's the non-generic approach:
using System.Collections.Generic;
using System;
public interface IOperand
{
object Value { get; }
bool IsEmpty { get; }
}
public abstract class Operand<T> : IOperand
{
public T Value { get; protected set; }
object IOperand.Value { get { return Value; } }
public bool IsEmpty { get; protected set; }
public override string ToString()
{
return IsEmpty ? Value.ToString() : string.Empty;
}
}
public class DoubleOperand : Operand<double> { }
public interface IOperandFactory
{
IOperand CreateEmptyOperand();
IOperand CreateOperand(object value);
}
public interface IOperandFactory<T> : IOperandFactory
{
new Operand<T> CreateEmptyOperand();
Operand<T> CreateOperand(T value);
}
public class DoubleFactory : IOperandFactory<double>
{
public Operand<double> CreateEmptyOperand()
{
throw new NotImplementedException();
}
IOperand IOperandFactory.CreateEmptyOperand() {
return CreateEmptyOperand();
}
IOperand IOperandFactory.CreateOperand(object value) {
return CreateOperand((double)value);
}
public Operand<double> CreateOperand(double value)
{
throw new NotImplementedException();
}
}
static class Program
{
static void Main()
{
var factoryDict = new Dictionary<Type, IOperandFactory> {
{typeof (double), new DoubleFactory()}
};
}
}
If I understand correctly, you are trying to store a collection of generic types, where the generic type parameters may vary. If this is the case, it is not directly possible, as the following example illustrates:
// You have lists of different types:
List<double> doubleCollection = new List<double>();
List<string> stringCollection = new List<string>();
// Now to store generically:
var collection = new List<List< /* ... Which type parameter to use? ... */ >>();
What should be apparent here, is that it is not possible to deduce which type parameter to use. Instead (with regards to your example), you may want something like this instead:
public interface IOperand
{
}
public interface IOperand<T>
{
}
public interface IOperandFactory
{
IOperand CreateEmptyOperand();
IOperand CreateOperand(object value);
}
public interface IOperandFactory<T> : IOperandFactory
{
new IOperand<T> CreateEmptyOperand();
IOperand<T> CreateOperand(T value);
}
public class DoubleFactory : IOperandFactory<double>
{
public IOperand<double> CreateEmptyOperand()
{
throw new NotImplementedException();
}
public IOperand<double> CreateOperand(double value)
{
throw new NotImplementedException();
}
IOperand IOperandFactory.CreateEmptyOperand()
{
throw new NotImplementedException();
}
public IOperand CreateOperand(object value)
{
throw new NotImplementedException();
}
}
public class SomeContainer
{
public SomeContainer()
{
var factoryDict = new Dictionary<Type, IOperandFactory>()
{
{ typeof(double), (IOperandFactory)new DoubleFactory() }
};
}
}
This may not be the most elegant of solutions, but it would allow you to store different generic types in the same collection. An issue with this, however, is that the caller accessing such a collection would need to know what type to cast to. For example:
// ... Inside SomeContainer ...
public IOperandFactory<T> GetFactory<T>()
{
return (IOperandFactory<T>)factoryDict[typeof(T)];
}
So with this, you can get the DoubleFactory using:
IOperandFactory<double> doubleFactory = mSomeContainerInstance.GetFactory<double>();
IOperand<double> emptyOperand = doubleFactory.CreateEmptyOperand();
IOperand<double> filledOperand = doubleFactory.CreateOperand(1.0d);

Categories