I have a method that looks more or less like this:
ConcreteType Find(IEnumerable<ConcreteType> values)
It iterates an IEnumerable
and at some point will return one of the values contained as a result. This method is not under my control and I cannot change it.
I need to wrap this method in another method that should look like this:
T Find(IEnumerable<T> values, Func<T,ConcreteType> map)
Having a generic type T
. This method should call the method above by mapping all values from T
to the ConcreteType
and then later map the ConcreteType
that was returned back to the original T
.
What is the easiest way to do this?
Important: The enumerable is evaluated dynamically (LINQ) and the map
method can be slow. So the solution is not allowed to iterate the enumerable more than the original Find
has to do and the map method should also only be called for values that are actually requested by the original Find
method.
You can assume that all values (T
or ConcreteType
) are unique so there is no possibility of one ConcreteType
mapping to various T
or vice versa.
Example:
If the above is too abstract, here is an concrete example:
// Original method
byte[] FindMatchingBuffer(IEnumerable<byte[]> values)
// Wrapper (TODO)
T FindMatchingBuffer(IEnumerable<T> values, Func<T, byte[]> map)
// Sample call
string matchingFileName = FindMatchingBuffer(fileNames, File.ReadAllBytes);
Thanks!
This answer is equivalent to that of C.Evenhuis, but uses an iterator block instead of a whole separate class:
T Find(IEnumerable<T> values, Func<T, ConcreteType> map)
{
var dictionary = new Dictionary<ConcreteType, T>();
ConcreteType found = Find(MapAndRecord(values, map, reverseMapping));
// TODO: Handle the situation where it's not found. (Does Find
// return null?)
return dictionary[found];
}
private static IEnumerable<ConcreteType> MapAndRecord(
IEnumerable<T> values, Func<T, ConcreteType> map,
IDictionary<ConcreteType, T> reverseMapping)
{
foreach (var value in values)
{
var mapped = map(value);
reverseMapping[mapped] = value;
yield return mapped;
}
}
See more on this question at Stackoverflow