C# 包装方法,使其与映射方法通用
我有一个方法大致如下:C# 包装方法,使其与映射方法通用,c#,.net,linq,generics,functional-programming,C#,.net,Linq,Generics,Functional Programming,我有一个方法大致如下: ConcreteType Find(IEnumerable<ConcreteType> values) T Find(IEnumerable<T> values, Func<T,ConcreteType> map) 具有泛型的T。此方法应通过将T中的所有值映射到ConcreteType来调用上述方法,然后将返回的ConcreteType映射回原始T 最简单的方法是什么 重要提示:可枚举项是动态计算的(LINQ),而map方法可能很慢
ConcreteType Find(IEnumerable<ConcreteType> values)
T Find(IEnumerable<T> values, Func<T,ConcreteType> map)
具有泛型的T
。此方法应通过将T
中的所有值映射到ConcreteType
来调用上述方法,然后将返回的ConcreteType
映射回原始T
最简单的方法是什么
重要提示:可枚举项是动态计算的(LINQ),而map
方法可能很慢。因此,解决方案迭代可枚举项的次数不允许超过原始Find
必须完成的次数,并且map方法也应该只对原始Find
方法实际请求的值进行调用
您可以假设所有值(T
或ConcreteType
)都是唯一的,因此不可能有一个ConcreteType
映射到各种T
,反之亦然
示例:
如果上述内容过于抽象,下面是一个具体的例子:
// 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);
//原始方法
字节[]FindMatchingBuffer(IEnumerable值)
//包装器(TODO)
T FindMatchingBuffer(IEnumerable值,Func映射)
//抽样电话
string matchingFileName=FindMatchingBuffer(文件名,File.ReadAllBytes);
谢谢 您可以实现
IEnumerator
(byte[]
在您的示例中)将IEnumerator
和map函数作为构造函数参数,并保留所有映射项的字典(因为我们不知道Find
在找到匹配项后是否停止迭代)
返回Find
后,您可以TryGetInputValue
再次获取文件名
(我不是LINQ用户,但我确信这可以包装成LINQable)
公共密封类查找枚举器:IEnumerator
{
私有只读IEnumerator输入;
私有只读Func映射;
私有只读字典反向=新字典();
公共查找枚举器(IEnumerator输入,函数映射)
{
这个输入=输入;
this.map=map;
}
公共电流
{
得到;
私人设置;
}
公共布尔TryGetInputValue(Y值、out T输入值)
{
返回反向.TryGetValue(值,输出输入值);
}
对象IEnumerator.Current
{
获取{返回当前;}
}
公共图书馆
{
如果(!input.MoveNext())
{
返回false;
}
当前=映射(输入。当前);
反向。添加(当前,输入。当前);
返回true;
}
//…IEnumerator实现的其余部分
此答案与C.Evenhuis的答案相同,但使用迭代器块而不是整个单独的类:
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;
}
}
T查找(IEnumerable值,Func映射)
{
var dictionary=newdictionary();
ConcreteType found=Find(映射记录(值、映射、反向映射));
//TODO:处理找不到的情况。(找到了吗?)
//返回空值?)
返回字典[找到];
}
私有静态IEnumerable映射记录(
IEnumerable值,Func映射,
索引反向映射)
{
foreach(值中的var值)
{
映射的var=映射(值);
反向映射[映射]=值;
收益率映射;
}
}
你能保证你不能更改的方法只能按需要进行迭代吗?换句话说,你能返回它获取的最后一个值吗?@JonSkeet我知道该方法只能按需要进行迭代。所以,是的,我可以返回捕获的最后一个值。尽管我认为这样的解决方案对我来说有点脏……你是个我会说,本质上是在一个肮脏的环境中。你有没有任何保证可以比较ConcreteType
的实例是否相等?将ConcreteType
的所有映射实例存储在内存中是否有问题?在你给出的示例中,这两个都是一个难题-你可能不想保留所有数据库的所有数据你读过的文件。是的,我知道ConcreteType的实例,因为我自己正在“制作”它们和假定的“合同”该方法的优点是它总是返回列表中的一个项或null。ConcreteType都是不同的,可以通过引用进行比较。不需要按值进行比较。此外,尽管必须将数据保存在内存中并不好,但这不会是一个问题,因为所有值的完整总和预计将小于几兆字节,而且我已经准备好了无论如何,缓存其中的一些值是很昂贵的,因为加载它们是很昂贵的。是的,这肯定会起作用。我正在寻找一种更简单的方法,尽管它不需要整个枚举器实现。。。
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;
}
}