存储指向方法参数的指针以供以后重用
本文关键字:指针 方法 参数 存储 | 更新日期: 2023-09-27 18:16:42
类似于带有自由变量的lambda表达式的工作方式,我想实现自己的闭包类,该类捕获一些方法参数。
public class Closure<TObject, TVariable>
{
public TVariable Variable { get; set; }
public Func<TObject, bool> Predicate { get; set; }
}
然后我有一些类可以使用DateTime
实例。应该使用这个闭包类的方法之一是:
// Original Version
public IEnumerable<Item> GetDayData(DateTime day)
{
this.items.Where(i => i.IsValidForDay(day));
}
我想将其转换为使用Closure
类。问题是我想重用(性能原因(我的Closure
类实例:
private Closure<Item, DateTime> closure = null;
public IEnumerable<Item> GetDayData(DateTime day)
{
if (closure == null)
{
this.closure = new Closure<Item, DateTime>() {
Variable = reference of "day" param, <=== HOW ????????
Predicate = i => i.IsValidForDay(this.closure.Variable)
}
}
this.items.Where(this.closure.Predicate);
}
为了重用同一个Closure
实例,我不必存储参数的值(到闭包的Variable
字段中(,而必须存储方法参数的引用指针。因此,下次调用这个方法时,闭包的Variable
实际上会指向要使用的正确值。
我该怎么做?
当编译器生成捕获lambda表达式自由变量的类时,也会执行类似的操作。我一直在研究反编译的代码(使用Reflector(,但我似乎不明白这是怎么做到的。。。
您的示例有点错误(这可能不会起作用,但语义/意图是正确的(:
private Closure<Item, DateTime> closure = null;
public IEnumerable<Item> GetDayData(DateTime day)
{
if (closure == null)
{
this.closure = new Closure<Item, DateTime>() {
Predicate = i => i.IsValidForDay(this.closure.Variable)
}
}
// assign here, else you only capture it the first time
closure.Variable = day;
this.items.Where(this.closure.Predicate);
}
可以引用局部变量,但这些是托管引用,不能存储在字段中。
编译器通过用字段替换局部变量来生成闭包。因此,它看起来像C#级别的局部变量,但像CLR级别的字段。
但在您的情况下,我看不出您为什么要通过引用来捕获局部变量。所以应该可以做一些你想做的事情:
public class Closure<TObject, TVariable>
{
public TVariable Variable { get; set; }
public Func<TVariable, TObject, bool> OpenPredicate { get; set; }
public bool ClosedPredicate(TObject o)
{
return OpenPredicate(this, o);
}
}
private Closure<Item, DateTime> closure = null;
public IEnumerable<Item> GetDayData(DateTime day)
{
if (closure == null)
{
this.closure = new Closure<Item, DateTime>() {
OpenPredicate = (closure, i) => i.IsValidForDay(closure.Variable)
}
}
closure.Variable=day;
this.items.Where(this.closure.ClosedPredicate);
}
但我认为这个代码是个坏主意。如果性能非常关键,请扔掉LINQ,自己动手。委托调用开销远大于创建一两个对象的开销。根据我的经验,LINQ通常比手工编写的代码慢2-3倍。
此外,此代码还创建了多个对象:
items.GetEumerator()
返回一,除非它是值类型或重新生成EnumerableWhere
返回新的IEnumerable
- 枚举函数的结果将创建另一个枚举器
- 每次都会获得一个新的委托实例
因此,我认为出于性能原因而绑定重用闭包是没有用的。
List<PicInfo> pi = new List<PicInfo>();
pi.Add(new PicInfo() { fileName = "a" });
pi.Add(new PicInfo() { fileName = "a" });
pi.Add(new PicInfo() { fileName = "b" });
pi.Add(new PicInfo() { fileName = "b" });
pi.Add(new PicInfo() { fileName = "a" });
string a = "a";
Closure<PicInfo, string> cl = null;
cl = new Closure<PicInfo, string>() {
Variable = a,
predicate = (i => i.fileName == cl.Variable.ToString())
};
MessageBox.Show(pi.Where(cl.predicate).Count().ToString()); // shows 3
// Change variable value here
string b = "b";
cl.Variable = b;
MessageBox.Show(pi.Where(cl.predicate).Count().ToString()); // Shows 2
@Robert Koritnik,这对我有用,with your existing class
。如果您只想用现有实例更改变量,您可以设置为variable属性