Hi,
Please consider the following snippet from an implementation of the Interpreter pattern:
public override object Execute(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable<string>;
return (list != null) ? list.FirstOrDefault() : null;
}
What about if I want to use the same function for integers?
public override object Execute(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable<string>;
if (list != null) return list.FirstOrDefault();
var list = ctx as IEnumerable<int>;
return (list != null) ? list.FirstOrDefault() : null;
}
What I wanted was something like:
public override object Execute(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable;
return (list != null) ? list.FirstOrDefault() : null;
}
But Linq doesn't act on IEnumerables. Instead, to get to this solution, I would be forced to write something like:
public override object Execute(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable;
if (list != null) foreach(var i in list) { yield return i; return; }
return null;
}
Or use a generic method:
public override T Execute<T>(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable<T>;
return (list != null) ? list.FirstOrDefault() : null;
}
Which would break the Interpreter pattern (as it was implemented in this system). Covariance would also fail (at least in C#3), though would it work, it would be the exact behavior I wanted:
public override object Execute(Interpreter interpreter, object ctx) {
var list = ctx as IEnumerable<object>;
return (list != null) ? list.FirstOrDefault() : null;
}
So, my question is: what's the best way to achieve the intended behavior?
Addendum: digEmAll suggested something like the following code:
var list = ctx as IEnumerable;
return (list != null) ? list.Cast<object>().FirstOrDefault() : null;
This is a good answer for stuff like FirstOrDefault(). The problem comes with things like Reverse:
var list = ctx as IEnumerable;
return (list != null) ? list.Cast<object>().Reverse() : null;
I could fed this method a List<int>
but I would get back a List<object>
. No way to get around covariance, I know. So I guess digEmAll code is the best answer so far.
Thanks :-)