При использовании блоков using() {} (sic), как показано ниже, и при условии, что cmd1 не находится за пределами области действия первого блока using() {}, почему второй блок должен генерировать исключение с сообщением
SqlParameter уже содержится в другой SqlParameterCollection
 Означает ли это, что ресурсы и/или дескрипторы, включая параметры (SqlParameterCollection), присоединенные к cmd1, не освобождаются, когда он уничтожается в конце блока?
using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Test;Integrated Security=True"))
{
    var parameters = new SqlParameter[] { new SqlParameter("@ProductId", SqlDbType.Int ) };
    using(var cmd1 = new SqlCommand("SELECT ProductName FROM Products WHERE ProductId = @ProductId"))
    {
        foreach (var parameter in parameters)
        {
            cmd1.Parameters.Add(parameter);                
        }
        // cmd1.Parameters.Clear(); // uncomment to save your skin!
    }
    using (var cmd2 = new SqlCommand("SELECT Review FROM ProductReviews WHERE ProductId = @ProductId"))
    {
        foreach (var parameter in parameters)
        {
            cmd2.Parameters.Add(parameter);
        }
    }
}
 ПРИМЕЧАНИЕ. Выполнение cmd1.Parameters.Clear() непосредственно перед последней скобкой первого блока using() {} избавит вас от исключения (и возможного затруднения).
Если вам нужно воспроизвести, вы можете использовать следующие сценарии для создания объектов:
CREATE TABLE Products
(
    ProductId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    ProductName nvarchar(32) NOT NULL
)
GO
CREATE TABLE ProductReviews
(
    ReviewId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    ProductId int NOT NULL,
    Review nvarchar(128) NOT NULL
)
GO