这可以通过 Lambda/Block 初始化来简化吗?
Can this be simplified with Lambda/Block initialization?
一直在 Swift 和 C# 之间来回摇摆,我不确定我是否忘记了某些事情,或者 C# 是否不容易支持我所追求的。
考虑这段代码,它计算 Foo
的初始值:
// Note: This is a field on an object, not a local variable.
int Foo = CalculateInitialFoo();
static int CalculateInitialFoo() {
int x = 0;
// Perform calculations to get x
return x;
}
有没有什么方法可以做这样的事情而不需要创建单独的一次性使用函数,而是使用立即执行的 lambda/block/whatever?
在Swift中,很简单。您使用立即执行的闭包(大括号)(左括号和右括号),如下所示:
int Foo = {
int x = 0
// Perform calculations to get x
return x
}()
它清晰、简洁,不会将对象的接口与仅用于初始化字段的函数混淆。
注意:明确地说,我不想要计算的属性。我正在尝试初始化一个需要多个语句才能完成的成员字段。
我不建议这样做,但你可以使用匿名函数来初始化
int _foo = new Func<int>(() =>
{
return 5;
})();
您是否有理由希望使用 lambda 而不是命名函数,或者作为计算结果 属性?
我假设您希望避免计算属性,因为您希望稍后修改该值,或者计算成本很高并且您希望缓存该值。
int? _fooBacking = null;
int Foo
{
get
{
if (!_fooBacking.HasValue)
{
_fooBacking = 5;
}
return _fooBacking.Value;
}
set
{
_fooBacking = value;
}
}
这将使用您在第一次获得条件时评估的内容,同时仍允许分配该值。
如果删除 setter,它将变成缓存计算。不过,使用此模式时要小心。 属性 吸气剂中的副作用会让人不悦,因为它们使代码难以理解。
要解决一般情况下的问题,您需要创建并执行一个匿名函数,从技术上讲,您可以将其作为表达式来执行:
int Foo = new Func<int>(() =>
{
int x = 0;
// Perform calculations to get x
return x;
})();
您可以通过编写辅助函数稍微清理一下:
public static T Perform<T>(Func<T> function)
{
return function();
}
这让你写:
int Foo = Perform(() =>
{
int x = 0;
// Perform calculations to get x
return x;
});
虽然这比第一个好,但我认为很难说 比只写一个函数更好。
在非一般情况下,许多特定的实现可以在单行而不是多行上更改为 运行。这样的解决方案在您的情况下可能是可行的,但我们不可能在不知道它是什么的情况下说出来。在某些情况下,这是 可能 但不受欢迎的情况,而在某些情况下,这实际上可能更可取。哪个是哪个当然是主观的。
您可以在构造函数中初始化您的字段并将 CalculateInitialFoo
声明为局部函数。
private int _foo;
public MyType()
{
_foo = CalculateInitialFoo();
int CalculateInitialFoo()
{
int x = 0;
// Perform calculations to get x
return x;
}
}
这不会对您的代码进行太多更改,但您至少可以将方法的范围限制在仅使用它的地方。
一直在 Swift 和 C# 之间来回摇摆,我不确定我是否忘记了某些事情,或者 C# 是否不容易支持我所追求的。
考虑这段代码,它计算 Foo
的初始值:
// Note: This is a field on an object, not a local variable.
int Foo = CalculateInitialFoo();
static int CalculateInitialFoo() {
int x = 0;
// Perform calculations to get x
return x;
}
有没有什么方法可以做这样的事情而不需要创建单独的一次性使用函数,而是使用立即执行的 lambda/block/whatever?
在Swift中,很简单。您使用立即执行的闭包(大括号)(左括号和右括号),如下所示:
int Foo = {
int x = 0
// Perform calculations to get x
return x
}()
它清晰、简洁,不会将对象的接口与仅用于初始化字段的函数混淆。
注意:明确地说,我不想要计算的属性。我正在尝试初始化一个需要多个语句才能完成的成员字段。
我不建议这样做,但你可以使用匿名函数来初始化
int _foo = new Func<int>(() =>
{
return 5;
})();
您是否有理由希望使用 lambda 而不是命名函数,或者作为计算结果 属性?
我假设您希望避免计算属性,因为您希望稍后修改该值,或者计算成本很高并且您希望缓存该值。
int? _fooBacking = null;
int Foo
{
get
{
if (!_fooBacking.HasValue)
{
_fooBacking = 5;
}
return _fooBacking.Value;
}
set
{
_fooBacking = value;
}
}
这将使用您在第一次获得条件时评估的内容,同时仍允许分配该值。
如果删除 setter,它将变成缓存计算。不过,使用此模式时要小心。 属性 吸气剂中的副作用会让人不悦,因为它们使代码难以理解。
要解决一般情况下的问题,您需要创建并执行一个匿名函数,从技术上讲,您可以将其作为表达式来执行:
int Foo = new Func<int>(() =>
{
int x = 0;
// Perform calculations to get x
return x;
})();
您可以通过编写辅助函数稍微清理一下:
public static T Perform<T>(Func<T> function)
{
return function();
}
这让你写:
int Foo = Perform(() =>
{
int x = 0;
// Perform calculations to get x
return x;
});
虽然这比第一个好,但我认为很难说 比只写一个函数更好。
在非一般情况下,许多特定的实现可以在单行而不是多行上更改为 运行。这样的解决方案在您的情况下可能是可行的,但我们不可能在不知道它是什么的情况下说出来。在某些情况下,这是 可能 但不受欢迎的情况,而在某些情况下,这实际上可能更可取。哪个是哪个当然是主观的。
您可以在构造函数中初始化您的字段并将 CalculateInitialFoo
声明为局部函数。
private int _foo;
public MyType()
{
_foo = CalculateInitialFoo();
int CalculateInitialFoo()
{
int x = 0;
// Perform calculations to get x
return x;
}
}
这不会对您的代码进行太多更改,但您至少可以将方法的范围限制在仅使用它的地方。