Reputation: 3633
I am trying to loop through a list of generic objects call Condition<T>
to read the generic field Value
. I followed this question to be able to store the List<Condition<T>>
. The issue I am running into now is that I can't use the Value
field in my loop. What do I need to change in order to use the Value
field?
string url = "";
List<ConditionBase> Conditions = new List<ConditionBase>();
Conditions.Add(new Condition<int>(Field.Field1, 1, ConditionOperator.Equal))
Conditions.Add(new Condition<string>(Field.Field2, "test", ConditionOperator.NotEqual))
foreach (ConditionBase c in Conditions)
{
if (c.GetType() == typeof(string))
{
// c.Value throws an error
url += c.Field + " " + c.ConditionOperator + " '" + c.Value + "' and ";
}
else if (c.GetType() == typeof(DateTime))
{
// c.Value throws an error
url += c.Field + " " + c.ConditionOperator + " " + Helpers.FormatDate(c.Value) + " and ";
}
}
public interface ConditionBase
{
Field Field { get; set; }
ConditionOperator ConditionOperator { get; set; }
}
public class Condition<T> : ConditionBase
{
private Field _Field;
private T _Value;
private ConditionOperator _ConditionOperator;
public Condition(Field field, T value, ConditionOperator condition)
{
this._Field = field;
this._Value = value;
this._ConditionOperator = condition;
}
public Field Field
{
get
{
return this._Field;
}
set
{
if (this._Field != value)
{
this._Field = value;
}
}
}
public T Value
{
get
{
return this._Value;
}
set
{
if (!EqualityComparer<T>.Default.Equals(this._Value, value))
{
this._Value = value;
}
}
}
public ConditionOperator ConditionOperator
{
get
{
return this._ConditionOperator;
}
set
{
if (this._ConditionOperator != value)
{
this._ConditionOperator = value;
}
}
}
}
public enum Field{
Field1,
Field2
}
public enum ConditionOperator{
Equal,
NotEqual,
GreaterThan,
LessThan
}
This solution is based on the comments by @orhtej2 & the answer by @Igor.
static void Main(string[] args)
{
var x1 = new Condition<int>(new Field(), 123, ConditionOperator.Equal);
var x2 = new Condition<string>(new Field(), "test", ConditionOperator.Equal);
var x3 = new Condition<DateTime>(new Field(), new DateTime(2018,5,5), ConditionOperator.Equal);
var qqq = new List<ConditionBase>();
qqq.Add(x1);
qqq.Add(x2);
qqq.Add(x3);
foreach (ConditionBase c in qqq)
{
Console.WriteLine(c.GetValue());
}
Console.ReadLine();
}
public interface ConditionBase
{
Field Field { get; set; }
ConditionOperator ConditionOperator { get; set; }
string GetValue();
}
public class Condition<T> : ConditionBase
{
private Field _Field;
private T _Value;
private ConditionOperator _ConditionOperator;
public Condition(Field field, T value, ConditionOperator condition)
{
this._Field = field;
this._Value = value;
this._ConditionOperator = condition;
}
public Field Field
{
get
{
return this._Field;
}
set
{
if (this._Field != value)
{
this._Field = value;
}
}
}
public T Value
{
get
{
return this._Value;
}
set
{
if (!EqualityComparer<T>.Default.Equals(this._Value, value))
{
this._Value = value;
}
}
}
public ConditionOperator ConditionOperator
{
get
{
return this._ConditionOperator;
}
set
{
if (this._ConditionOperator != value)
{
this._ConditionOperator = value;
}
}
}
public string GetValue()
{
if (Value is string)
{
return "'" + Value.ToString() + "'";
}
else if (Value is DateTime)
{
return Helpers.FormatDate(Convert.ToDateTime(Value));
}
else
{
return Value.ToString();
}
}
}
public enum Field{
Field1,
Field2
}
public enum ConditionOperator{
Equal,
NotEqual,
GreaterThan,
LessThan
}
Upvotes: 2
Views: 457
Reputation: 62213
You have syntax errors in the code like the lacking public scope of your enums and ConditionOperator.Equal
(not ConditionOperator.Equals
) but that asside here is the fix.
Conditions
should be of type List<ConditionBase>
OfType
on the List to retrieve and cast the resulting type to Condition<string>
. I assume that this was your intention with your added check c.GetType() == typeof(string)
string url = "";
List<ConditionBase> Conditions = new List<ConditionBase>();
Conditions.Add(new Condition<int>(Field.Field1, 1, ConditionOperator.Equal));
Conditions.Add(new Condition<string>(Field.Field2, "test", ConditionOperator.NotEqual));
foreach (var c in Conditions.OfType<Condition<string>>())
{
url += c.Field + " " + c.ConditionOperator + " '" + c.Value + "' and ";
}
If you want a generic property that you can access on all instances regardless of the generic type constraint then you would need to extend the base interface accordingly.
public interface ConditionBase
{
Field Field { get; set; }
ConditionOperator ConditionOperator { get; set; }
object FieldValue { get; }
}
public class Condition<T> : ConditionBase
{
/* I only included the added code in this type */
public object FieldValue
{
get { return (object) this.Value; }
}
}
string url = "";
List<ConditionBase> Conditions = new List<ConditionBase>();
Conditions.Add(new Condition<int>(Field.Field1, 1, ConditionOperator.Equal));
Conditions.Add(new Condition<string>(Field.Field2, "test", ConditionOperator.NotEqual));
foreach (var c in Conditions)
{
url += c.Field + " " + c.ConditionOperator + " '" + c.FieldValue + "' and ";
}
It seems you want to output your value to a string based on the changes in your question. Add a string formatter to your type.
/* I only included the added code in this type */
public class Condition<T> : ConditionBase
{
private Func<T, string> _formatValue;
public Condition(Field field, T value, ConditionOperator condition, Func<T, string> formatValue)
{
this._Field = field;
this._Value = value;
this._ConditionOperator = condition;
this._formatValue = formatValue;
}
public override string ToString()
{
return this._formatValue(this.Value);
}
}
string url = "";
List<ConditionBase> Conditions = new List<ConditionBase>();
Conditions.Add(new Condition<int>(Field.Field1, 1, ConditionOperator.Equal, (val)=> val.ToString()));
Conditions.Add(new Condition<string>(Field.Field2, "test", ConditionOperator.NotEqual, (val)=> val));
foreach (var c in Conditions)
{
url += c.Field + " " + c.ConditionOperator + " '" + c.ToString() + "' and ";
}
Upvotes: 3