Enumeration depending on type T
I have a generic class that should constrain an enum based on a specific type:
public enum ConditionOperatorsString { None, Like, Equal }
public enum ConditionOperatorsDate { None, Equal, BeforeThan, AfterThan }
public class Condition<T>
{
public T Value { get; set; }
public ConditionOperatorsString Operator { get; set; }
public Condition(T Value, ConditionOperatorsString Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
Now the problem is that I want the Operator type to depend on T when:
Condition<string> CStr= new Condition<string>(string.Empty, ConditionOperatorsString.None)
Condition<DateTime> CStr= new Condition<DateTime>(DateTime.Now, ConditionOperatorsDate.None)
How do I define a class condition for this? I was thinking about interface, but enums don't inherit from interfaces.
There is no good way to do what you are trying to do without having something like:
if (typeof(T) == typeof(string) &&
typeof(Operator) != typeof(ConditionOperatorsString))
{
throw new Exception("Invalid conditionoperators value);
}
This is really not very useful as you have to know in advance all the different possibilities for T.
What you can do is something like this:
public abstract class ComparableBase<T,K>
{
public T Value { get; protected set; }
public K ConditionOperator { get; protected set; }
// public abstract bool IsMatch(T other); // Is this required?
protected ComparableBase(T value, K op)
{
this.Value = value;
this.ConditionOperator = op;
}
}
public enum ComparableOperator { None, Equal, Less, Greater }
public enum LikeOrEqualOperator { None, Like, Equal }
public class ComparableCondition<T> : ComparableBase<T,ComparableOperator>
{
public ComparableCondition(T value, ComparableOperator op):base(value, op)
{
}
}
public class LikeOrEqualCondition<T> : ComparableBase<T, LikeOrEqualOperator>
{
public LikeOrEqualCondition(T value, LikeOrEqualOperator op):base(value, op)
{
}
}
then you can declare
var condition1 = new LikeOrEqualCondition<string>("hi", LikeOrEqualOperator.Equal);
Do you need to have IsMatch
? Or it displays the selected filter without actually implementing it.
If you do, things get a little more complicated ...
source to share
Can the enum type just be another generic parameter, eg.
public enum ConditionOperatorsString { None, Like, Equal }
public enum ConditionOperatorsDate { None, Equal, BeforeThan, AfterThan }
public class Condition<T, TEnum>
{
public T Value { get; set; }
public TEnum Operator { get; set; }
public Condition(T Value, TEnum Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
Perhaps you need more information, but not 100% sure how it would mean to actually match the code that will use it
source to share
You must specify the enum type as a template parameter.
public class Condition<TValue, TOperator>
{
public TValue Value { get; private set; }
public TOperator Operator { get; private set; }
private Condition(TValue val, TOperator op)
{
Value = val;
Operator = op;
}
}
It would be nice to add where TOperator : Enum
, but I'm pretty sure the compiler doesn't allow it.
source to share
Thanks for answers.
I wanted to avoid having more than one class, but apparently this is not possible. Based on the last comment from silky, I ended up in the same solution as nader. Not optimal, but it does the enum constraint trick, the con is that the client needs to know there are n classes:
public abstract class ConditionBase<T, E>
{
public T Value { get; set; }
public E Operator { get; set; }
protected ConditionBase(T Value, E Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
public enum ConditionOperatorsString { None, Like, Equal }
public class ConditionString : ConditionBase<string, ConditionOperatorsString>
{
public ConditionString(String Value, ConditionOperatorsString Operator) : base(Value, Operator) { }
}
public enum ConditionOperatorsDate { None, Like, BeforeThan, AfterThan }
public class ConditionDate : ConditionBase<DateTime?, ConditionOperatorsDate>
{
public ConditionDate(DateTime? Value, ConditionOperatorsDate Operator) : base(Value, Operator) { }
}
Client Usage:
ConditionString StrCond = new ConditionString(string.Empty, ConditionOperatorsString.None);
ConditionDate DateCond = new ConditionDate(DateTime.MinValue, ConditionOperatorsDate.None);
I wanted to be able to use something like:
ConditionGeneric StrCond = new ConditionGeneric(string.Empty, ConditionOperatorsString.None);
ConditionGeneric DateCond = new ConditionGeneric(DateTime.MinValue, ConditionOperatorsDate.None);
ConditionGeneric InvalidStrCond = new ConditionGeneric(string.Empty, ConditionOperatorsDate.None);
ConditionGeneric InvalidDateCond = new ConditionGeneric(DateTime.MinValue, ConditionOperatorsString.None);