Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 包装方法,使其与映射方法通用_C#_.net_Linq_Generics_Functional Programming - Fatal编程技术网

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;
    }
}