Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Add TryAdd/Remove extension methods in CollectionExtensions#18091

Merged
safern merged 12 commits into
dotnet:masterfrom
nbarbettini:17918-AddDictionaryAddRemoveExtensions
Apr 16, 2017
Merged

Add TryAdd/Remove extension methods in CollectionExtensions#18091
safern merged 12 commits into
dotnet:masterfrom
nbarbettini:17918-AddDictionaryAddRemoveExtensions

Conversation

@nbarbettini
Copy link
Copy Markdown
Member

Adding TryAdd and Remove to CollectionExtensions.

Hopefully I did everything correctly. If not, I'm happy to revise the PR 😄

cc @safern @karelz @danmosemsft

Closes #17918

@dnfclas
Copy link
Copy Markdown

dnfclas commented Apr 7, 2017

@nbarbettini,
Thanks for your contribution.
To ensure that the project team has proper rights to use your work, please complete the Contribution License Agreement at https://cla2.dotnetfoundation.org.

It will cover your contributions to all .NET Foundation-managed open source projects.
Thanks,
.NET Foundation Pull Request Bot


namespace System.Collections.Generic
{
internal static class DictionaryExtensions
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is superseded by adding TryAdd to CollectionExtensions?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually still needed. Dictionary.TryAdd only exists in .NET Core, not in desktop (.NET Framework), so this extension method is used by the tests when compiled for desktop to provide a polyfill.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we would need to add the Remove API that is being added to CollectionExtensions in order for all the tests to pass in Desktop right, @stephentoub ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Or alternatively include the product CollectionExtensions file into the test project when building for desktop, if that's feasible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I removed this is because was an ambiguous call with the new Collection.ExtensionsTryAdd. I'll investigate resolving the problem re: desktop.

Copy link
Copy Markdown
Member

@safern safern Apr 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could wrap this type around an #if !netcoreapp

TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionCngProvider' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionCspProvider' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionKeyStoreProvider' does not exist in the implementation but it does exist in the contract.
CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlCommand' does not implement interface 'System.ICloneable' in the implementation but it does in the contract.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure why these showed up - I didn't change anything in System.Data.SqlClient. Should these be ignored?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is created/updated automatically when running build.cmd and getting a successful build. This is a diff in APIs we have in between netcoreapp and desktop. So don't worry about this. You can either remove this change from your PR or leave it, sooner or later it will get updated.

@nbarbettini
Copy link
Copy Markdown
Member Author

FYI, I can squash some of these commits if you'd like. I had a little bit of churn while I was figuring out how everything worked.

@dnfclas
Copy link
Copy Markdown

dnfclas commented Apr 7, 2017

@nbarbettini, thanks for signing the contribution license agreement. We will now validate the agreement and then the pull request.

Thanks, .NET Foundation Pull Request Bot

@safern
Copy link
Copy Markdown
Member

safern commented Apr 7, 2017

Thanks for doing this!

I think deleting DictionaryExtensions.cs broke some other test projects that used this file that is why you are getting a lot of CI failures. To get a local repro an fix it you will have to build the tests locally for every target framework:

Netcoreapp:

From your repo root run the following commands:

  • build.cmd
  • build-tests.cmd -skiptests

Netfx:

From your repo root run the following commands:

  • build.cmd -framework:netfx
  • build-tests.cmd -skiptests -framework:netfx

Uap:

From your repo root run the following commands:

  • build.cmd -framework:uap
  • build-tests.cmd -skiptests -framework:uap

UapAot:

From your repo root run the following commands:

  • build.cmd -framework:uapaot
  • build-tests.cmd -skiptests -framework:uapaot

[EDIT]: @stephentoub is right we need that file for the tests in Desktop to pass.

}

return false;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't ever removing the value from the dictionary.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(which also highlights that the new tests are missing verification that the value is actually removed)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent point... d'oh. Fixed. 👍

@safern
Copy link
Copy Markdown
Member

safern commented Apr 7, 2017

To run the tests in Desktop and verify that the new tests that you added are passing you can run from your repo's root:

  • build.cmd -framework:netfx
  • msbuild src\System.Collections\tests\System.Collections.Tests.csproj /t:rebuildandtest /p:TargetGroup=netfx

<Link>Common\System\ObjectCloner.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Collections\DictionaryExtensions.cs">
<Link>Common\System\Collections\DictionaryExtensions.cs</Link>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is around 7 other projects that use DictionaryExtensions.cs file.

That is why CI is failing. You could verify this by running:
build.cmd
build-tests.cmd -skiptests

Can we leave this file as it was and add the new API there as well? Since there is a lot of test projects that use this file.

public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue()
{
IDictionary<string, string> dictionary = new SortedDictionary<string, string>();
Assert.Equal(true, dictionary.TryAdd("key", "value"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Assert.True or Assert.False instead of direct equality checks for booleans

throw new ArgumentNullException(nameof(dictionary));
}

value = default(TValue);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved down to where false is returned.


value = default(TValue);

if (dictionary.TryGetValue(key, out var foundValue))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use a temporary? You can just use out value.

@nbarbettini
Copy link
Copy Markdown
Member Author

Thanks for the great feedback (and patience) y'all. Had to step out for a bit and didn't get back to it until now.

I reverted my deletion of DictionaryExtensions because I realize that's the wrong path to go down. There are some tests still failing because of an ambiguous call between the TryAdd in DictionaryExtensions and my new TryAdd. (I'm sure it's something simple, I'll keep working on it)

Thanks for sticking with me 😄

@safern
Copy link
Copy Markdown
Member

safern commented Apr 11, 2017

Thanks for the update... please let us know if you are not able to figure it out so that we can guide you.

@danmoseley
Copy link
Copy Markdown
Member

@dotnet-bot test this please (logs gone)

@nbarbettini
Copy link
Copy Markdown
Member Author

nbarbettini commented Apr 16, 2017

Sorry for the delay, it's been a busy week!

Thanks for the hints @safern and @stephentoub. I was able to get all the tests to pass by selectively excluding the DictionaryExtensions file in the targets that don't need the shim. It could also be done with an #if !netcoreapp conditional in the file itself; is that preferable, or is this way preferable?

Let me know how it's looking, and if there's anything else I need to do. I can rebase the PR, and/or squash some of the churn in the history if you want.

@safern
Copy link
Copy Markdown
Member

safern commented Apr 16, 2017

Sorry for the delay, it's been a busy week!

No worries!

Actually we rather do it the way you did it. I gave you another option in case you got blocked, but the way you did it is excellent. Thanks for the update.

The other thing you need to do now is fix your merge conflicts by fetching the latest changes in dotnet/master and rebasing your changes on top of it. Then update your PR. See: #18109 (comment) as a guidance. To update the PR after doing that you will have to do a force push.

@nbarbettini nbarbettini force-pushed the 17918-AddDictionaryAddRemoveExtensions branch from d6e7a33 to e5f005b Compare April 16, 2017 21:01
@nbarbettini
Copy link
Copy Markdown
Member Author

@safern Rebased and resolved conflicts. 👍

public void Remove_NullKeyIDictionary_ThrowsArgumentNullException()
{
IDictionary<string, string> dictionary = new SortedDictionary<string, string>();
Assert.Throws<ArgumentNullException>("key", () => dictionary.Remove(null, out var value));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done. 👍

public void Remove_NullIDictionary_ThrowsArgumentNullException()
{
IDictionary<string, string> dictionary = null;
Assert.Throws<ArgumentNullException>("dictionary", () => dictionary.Remove("key", out var value));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could assign a value to the out parameter before calling Remove and test that the value did not changed when an exception is thrown.

Copy link
Copy Markdown
Member

@safern safern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @nbarbettini for contributing. Feel free to grab any issue with milestone 2.0.0. When grabbing the issue just ping on it so that we can assign it to you and we don't have two people working on the same issue.

@nbarbettini
Copy link
Copy Markdown
Member Author

Thanks @safern et al! 🎉 I'm really glad to be able to contribute.

@safern safern merged commit c8ed5b6 into dotnet:master Apr 16, 2017
@nbarbettini nbarbettini deleted the 17918-AddDictionaryAddRemoveExtensions branch April 16, 2017 22:58
WinCPP pushed a commit to WinCPP/corefx that referenced this pull request Apr 18, 2017
WinCPP pushed a commit to WinCPP/corefx that referenced this pull request Apr 18, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants