c# - c# : how do I nest using statements and allow code blocks to modify returned data? 中的函数式编程

标签 c# generics functional-programming nested-generics

我正在全神贯注于 C# 中的函数式编程,这样我就可以减少代码中的副作用数量,并使测试更容易并泛化我的代码,从而使重构更容易。但是,我在弄清楚如何使用通用 using block 嵌套 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 语句,但对返回的项目进行了修改,我想传递怎么办?

通过重用我在上面 stub 的 Disposable 类来考虑以下内容:

        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 的 加密模式怎么办?

以下不起作用:

        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 方法传递的变量?

最佳答案

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

这是由于 subtle difference lambda 函数和匿名 方法之间。

关于c# - c# : how do I nest using statements and allow code blocks to modify returned data? 中的函数式编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37139546/

相关文章:

clojure - 如何在 Clojure 宏中包装异常?

javascript - 将数组部分映射到新数组

c# - 如何将新输入的项目保存到组合框项目源中?

c# - 找到多个与请求 http post 方法匹配的操作

c# - 是否可以通过管道传输分隔格式编码值而不是逗号?

java - 泛型和 <E extends ...> 的问题

java - java foreach循环中的数组引用

c# - FindByIdentity 在 ASP.NET webapp 中因 PricipalOperationException 而失败

c# - 使用 Linq 比较两个通用列表

scala - 何时使用单例对象以及何时在 scala 中使用实际对象