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
Related
I need to be able to access a protected property/method on an object with the common base class to the calling scope. The compiler doesn't seem to like this at all.
class Base
{
protected int Data { get; set; }
}
class SubClasss1 : Base
{
}
class SubClasss2 :Base
{
public SubClasss1 MyFunction() {
SubClasss1 x = new SubClasss1();
x.Data = this.Data; // NOT HAPPY
return x;
}
}
I've figured this may work, but it doesn't
((Base)copy).Data = ...
This does work but is a bit ugly
class Base
{
protected int Data { get; set; }
protected int GetData(Base obj) { return obj.Data; }
protected void SetData(Base obj, int value) { obj.Data = value; }
}
class SubClasss1 : Base
{
}
class SubClasss2 : Base
{
public SubClasss1 MyFunction()
{
SubClasss1 x = new SubClasss1();
this.SetData(x, this.Data);
return x;
}
}
I was trying to avoid using protected internal as I don't want to clutter the public interface within the project.
This is because protected member can be accessed with in the derived class not outside of it. What you can do is add it to constructor like:
class SubClasss1 : Base
{
public SubClasss1(int data)
{
Data = data; // can be accessed within the class but not from outside
}
}
and then you would need to provide it:
class SubClasss2 : Base
{
public SubClasss1 MyFunction()
{
SubClasss1 copy = new SubClasss1(this.Data);
return copy;
}
}
One way can be create public set method in SubClasss2 and then you should be able to read the value of it and set it into SubClass1 in your Myfucntion.
class Base
{
protected int Data { get; set; }
protected int GetData(Base obj) { return obj.Data; }
protected void SetData(Base obj, int value) { obj.Data = value; }
}
class SubClasss1 : Base
{
public void SetData(Base obj, int value) { this.Data = value; }
}
class SubClasss2 : Base
{
public void SetData(Base obj, int value) { this.Data = value; }
public SubClasss1 MyFunction()
{
SubClasss1 x = new SubClasss1();
x.SetData(x, this.Data);
return x;
}
}
class Program
{
static void Main(string[] args)
{
SubClasss2 subClass2Obj= new SubClasss2();
subClass2Obj.SetData(subClass2Obj, 30);
var subClass1Obj = subClass2Obj.MyFunction();
}
}
I would like to create an abstract class for hierarchical structured objects.
Here is what I already use, but now I want to make it generic
public class EventBase
{
private EventBase _Parent;
virtual public EventBase Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
}
}
[ForeignKey("Parent")]
private ICustomList<EventBase> _ChildList = new CustomList<EventBase>();
virtual public ICustomList<EventBase> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
}
}
}
something like this:
public class EventBaseGeneric
{
private GenericTypeThatIsSetInTheInheritingClass _Parent;
virtual public GenericTypeThatIsSetInTheInheritingClass Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
}
}
[ForeignKey("Parent")]
private ICustomList<GenericTypeThatIsSetInTheInheritingClass> _ChildList = new CustomList<GenericTypeThatIsSetInTheInheritingClass>();
virtual public ICustomList<GenericTypeThatIsSetInTheInheritingClass> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
}
}
}
Thanks a lot for any idea on how to achiv this !
Best regards,
Fabianus
It would look as follows:
// T generic parameter must inherit EventBase<T>
public class EventBase<T>
where T : EventBase<T>
{
public virtual T Parent { get; set; }
[ForeignKey("Parent")]
public virtual ICustomList<T> ChildList { get; set; } = new CustomList<T>()
}
I found the answer:
public abstract class PersistentObjectBaseWithNameHierarchical <T>
{
private T _Parent;
virtual public T Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
UpdatePropertiesInHierachy();
}
}
[ForeignKey("Parent")]
private ICustomList<T> _ChildList = new CustomList<T>();
virtual public ICustomList<T> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
UpdatePropertiesInHierachy();
}
}
could it be that it has to go like this ?
public abstract class PersistentObjectBaseWithNameHierarchical<T> : PersistentObjectBaseWithName where T : PersistentObjectBaseWithNameHierarchical<T>
{
private PersistentObjectBaseWithNameHierarchical<T> _Parent;
virtual public PersistentObjectBaseWithNameHierarchical<T> Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
UpdatePropertiesInHierachy();
}
}
[ForeignKey("Parent")]
private ICustomList<PersistentObjectBaseWithNameHierarchical<T>> _ChildList = new CustomList<PersistentObjectBaseWithNameHierarchical<T>>();
virtual public ICustomList<PersistentObjectBaseWithNameHierarchical<T>> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
UpdatePropertiesInHierachy();
}
}
public void AddChild(PersistentObjectBaseWithNameHierarchical<T> child)
{
if (ChildList.Count() != 0)
child.OrderPosition = ChildList.Max(e => e.OrderPosition) + 1;
ChildList.Add(child);
}
public void OrderChildList()
{
foreach (var e in ChildList)
{
e.OrderChildList();
}
ChildList.Sort((s1, s2) => s1.OrderPosition.CompareTo(s2.OrderPosition));
}
public int Level
{
get
{
if (Parent != null)
{
return Parent.Level + 1;
}
else
{
return 1;
}
}
}
private double _OrderPosition;
virtual public double OrderPosition
{
get
{
if (_OrderPosition == 0)
{
// We use the Id as OrderPosition to keep creation order by default
_OrderPosition = Id;
}
return _OrderPosition;
}
set
{
_OrderPosition = value;
Parent?.ChildList.Sort((s1, s2) => s1.OrderPosition.CompareTo(s2.OrderPosition));
UpdatePropertiesInHierachy();
}
}
public void UpdatePropertiesInHierachy()
{
PersistentObjectBaseWithNameHierarchical<T> r = GetRoot(this);
DuringUpdatePropertiesInHierachy();
}
Because otherwise I get an error here:
GetRoot(this)
telling
Argument 1: cannot convert from 'HostSystems.Models.PersistentObjectBaseWithNameHierarchical' to 'T'
Thanks for any further advice !
Regards,
Fabianus
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.
I have the following code for supporting a list of different types :
public enum eType
{
tInt,
tString,
tDateTime
}
public interface ICustomType<out T>
{
T Value { get; }
}
public abstract class DifferentType
{
protected DifferentType(eType type, string mnemonic)
{
Type = type;
Mnemonic = mnemonic;
}
public string Mnemonic { get; private set; }
public eType Type { get; private set; }
}
public class DateTimeType : DifferentType, ICustomType<DateTime>
{
public DateTimeType(DateTime value, string mnemonic)
: base(eType.tDateTime, mnemonic)
{
Value = value;
}
public DateTime Value { get; private set; }
}
public class IntType : DifferentType, ICustomType<int>
{
public IntType(int value, string mnemonic)
: base(eType.tInt, mnemonic)
{
Value = value;
}
public int Value { get; private set; }
}
public class StringType : DifferentType, ICustomType<string>
{
public StringType(string value, string mnemonic)
: base(eType.tString, mnemonic)
{
Value = value;
}
public string Value { get; private set; }
}
public static class UtilValue
{
public static T GetValue<T>(DifferentType customType)
{
return ((ICustomType<T>)customType).Value;
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { GetInt(), GetString(), GetDate() };
foreach (var i in values)
{
switch (i.Type)
{
case eType.tInt:
int resInt = UtilValue.GetValue<int>(i);
break;
case eType.tString:
string resString = UtilValue.GetValue<string>(i);
break;
case eType.tDateTime:
DateTime resDateTime = UtilValue.GetValue<DateTime>(i);
break;
}
}
}
private DateTimeType GetDate()
{
return new DateTimeType(new DateTime(2000, 1, 1), "MnemonicDate");
}
private IntType GetInt()
{
return new IntType(5, "MnemonicInt");
}
private StringType GetString()
{
return new StringType("ok", "MnemonicString");
}
}
and would like to avoid the cast at line return ((ICustomType<T>)customType).Value; in the UtilValue class, any idea how I can get rid of that while still keeping the design?
I am not even sure if this cast is expensive to do? My guess is most certainly.
Visitor-pattern example:
interface IDifferentTypeVisitor
{
void Visit(DateTimeType dt);
void Visit(StringType st);
}
class DifferentType
{
public abstract void Accept(IDifferentTypeVisitor visitor);
}
class DateTimeType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class StringType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class SomeVisitor : IDifferentTypeVisitor
{
public void Visit(DateTimeType dt)
{
//DateTime resDateTime = dt.Value; Or similar
}
public void Visit(StringType st)
{
//string resString = st.Value; Or similar
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { /* Content */ };
var visitor = new SomeVisitor();
foreach (var i in values)
{
i.Accept(visitor);
}
}
}
In C# 4 with dynamic it's possible to save some code by adding this to DifferentType:
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit((dynamic)this);
}
and then delete all other Accept methods. It hurts performance but it looks better ;-)
Suppose class A as:
public class A
{
private string _str;
private int _int;
public A(string str)
{
this._str = str;
}
public A(int num)
{
this._int = num;
}
public int Num
{
get
{
return this._int;
}
}
public string Str
{
get
{
return this._str;
}
}
}
I want to hide Str property when i construct class A as
new A(2)
and want to hide Num property when i construct class A as
new A("car").
What should i do?
That isn't possible with a single class. An A is an A, and has the same properties - regardless of how it is constructed.
You could have 2 subclasses of abstract A, and a factory method...
public abstract class A
{
class A_Impl<T> : A
{
private T val;
public A_Impl(T val) { this.val = val; }
public T Value { get { return val; } }
}
public static A Create(int i) { return new A_Impl<int>(i); }
public static A Create(string str) { return new A_Impl<string>(str); }
}
But : the caller will not know about the value unless they cast it.
use generics
public class A<T>
{
private T _value;
public A(T value)
{
this._value= value;
}
public TValue
{
get
{
return this._value;
}
}
}