c# 中的函数式编程:如何嵌套 using 语句并允许代码块修改返回的数据?
Functional programming in c#: how do I nest using statements and allow code blocks to modify returned data?
我正在全神贯注于 C# 中的函数式编程,这样我就可以减少代码中的副作用数量,并使测试更容易并泛化我的代码,从而使重构更容易。但是,我在弄清楚如何使用通用 using 块嵌套 using
语句时遇到问题。考虑以下因素:
public static class Disposable
{
public static TResult Using<TDisposable, TResult>
(
Func<TDisposable> factory,
Func<TDisposable, TResult> fn) where TDisposable : IDisposable
{
using (var disposable = factory())
{
return fn(disposable);
}
}
}
我使用以下代码示例调用此代码:
Disposable.Using(
StreamFactory.GetStream,
stream => new byte[stream.Length].Tee(b => stream.Read(b, 0, (int)stream.Length)))
然后我将修改后的 using
语句的输出传递给管道中的另一个方法。
然而,我确实遇到了一个警告,我被困在那里。
如果我想使用嵌套的 using 语句,但对返回的项目进行了修改,我想传递怎么办?
通过重用我在上面存根的 Disposable
class 来考虑以下内容:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor)
));
此代码有效...但是,如果我想更改 symmetricKey's
加密模式怎么办?
以下无效:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC; // ← this causes an issue, and also the fact that I made a **code block** here
Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}
));
如何修改通过我在上面创建的广义 Disposable.Using
方法传递的变量?
我认为您只是缺少一个 return
。试试这个。
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC;
return Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}));
What if I want to use nested using statements, but make modifications to items returned that I want to pass along?
让我们从简化您的 Disposable.Using
开始,我们不需要通用的 TDisposable
-- 删除它,只需使用 IDisposable
.
public static class Disposable
{
public static TResult Using<TResult>(
Func<IDisposable> factory,
Func<IDisposable, TResult> use)
{
using (var disposable = factory())
{
return use(disposable);
}
}
}
此外,正如@juharr 提醒注意的那样 - 你错过了 return
:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC;
return Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}));
这是由于 lambda
函数和 anonymous
方法之间的 subtle difference。
我正在全神贯注于 C# 中的函数式编程,这样我就可以减少代码中的副作用数量,并使测试更容易并泛化我的代码,从而使重构更容易。但是,我在弄清楚如何使用通用 using 块嵌套 using
语句时遇到问题。考虑以下因素:
public static class Disposable
{
public static TResult Using<TDisposable, TResult>
(
Func<TDisposable> factory,
Func<TDisposable, TResult> fn) where TDisposable : IDisposable
{
using (var disposable = factory())
{
return fn(disposable);
}
}
}
我使用以下代码示例调用此代码:
Disposable.Using(
StreamFactory.GetStream,
stream => new byte[stream.Length].Tee(b => stream.Read(b, 0, (int)stream.Length)))
然后我将修改后的 using
语句的输出传递给管道中的另一个方法。
然而,我确实遇到了一个警告,我被困在那里。
如果我想使用嵌套的 using 语句,但对返回的项目进行了修改,我想传递怎么办?
通过重用我在上面存根的 Disposable
class 来考虑以下内容:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor)
));
此代码有效...但是,如果我想更改 symmetricKey's
加密模式怎么办?
以下无效:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC; // ← this causes an issue, and also the fact that I made a **code block** here
Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}
));
如何修改通过我在上面创建的广义 Disposable.Using
方法传递的变量?
我认为您只是缺少一个 return
。试试这个。
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC;
return Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}));
What if I want to use nested using statements, but make modifications to items returned that I want to pass along?
让我们从简化您的 Disposable.Using
开始,我们不需要通用的 TDisposable
-- 删除它,只需使用 IDisposable
.
public static class Disposable
{
public static TResult Using<TResult>(
Func<IDisposable> factory,
Func<IDisposable, TResult> use)
{
using (var disposable = factory())
{
return use(disposable);
}
}
}
此外,正如@juharr 提醒注意的那样 - 你错过了 return
:
Disposable.Using(
() => new PasswordDeriveBytes(PasswordConstants.CryptoKey, null),
password => Disposable.Using(
() => new RijndaelManaged(),
symmetricKey =>
{
symmetricKey.Mode = CipherMode.CBC;
return Disposable.Using(
() => symmetricKey.CreateEncryptor(password.GetBytes(PasswordConstants.KeySize/8), Encoding.ASCII.GetBytes(PasswordConstants.Cipher)),
encryptor => encryptor);
}));
这是由于 lambda
函数和 anonymous
方法之间的 subtle difference。