-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add dictionary .IfContainsKey()
.IfNotContainsKey()
#40
Comments
I want to develop this issue |
Oh boy - I'm sorry @beton-kun I did not see your first comment there today. |
I closed my first PR as the code only works with IDictionary-interface and not with the IDictionary<,> generic interface. The sample given in #40 works as the generic class Dictionary<,> implements the non-generic interface. @beton-kun : Your comment was right, where is it? As an alternative to another generic parameter perhaps we could have two extension-methods (one for |
@AndreasHoersken listen, gtfo from my issue |
@beton-kun are you serious? No collaboration here? Have fun then. Looking forward to your solution. |
+ = This is a library from the community for the community. No bullying or disrespectful comments will be tolerated. @AndreasHoersken, let me poke at this a little and we'll collaborate on a solution for this? |
Wow. Strange guy. Thanks @mantinband . Sorry for the inconvenience. I'll be happy to work on it further. If you have any ideas on the solution, please let me know. I can only work on it in the evenings though. |
@AndreasHoersken I see the issue you ran into. I had a similar issue with #20. There is a way to work around this, I prototyped it in the following PR: #25 Basically what we would have to do is:
public readonly record struct Validatable<TValue>(TValue Value, string ParamName, ExceptionCustomizations? ExceptionCustomizations = null)
: IValidatable<TValue> {}
public interface IValidatable<out TValue> {}
public static IValidatable<IDictionary<TKey, TValue>> IfContainsKey<TKey, TValue>(this IValidatable<IDictionary<TKey, TValue>> validatable, TKey key)
{
Console.WriteLine($"Contains key: {validatable.Value.ContainsKey(key)}");
return validatable;
}
IDictionary<string, string> dictionary1 = new Dictionary<string, string>
{
{ "key", "value" },
{ "key2", "value2" },
};
Dictionary<string, string> dictionary2 = new()
{
{ "key", "value" },
{ "key2", "value2" },
};
var dictionary3 = new ReadOnlyDictionary<string, string>(dictionary1);
var dictionary4 = new ConcurrentDictionary<string, string>(dictionary1);
// etc The only issue with this solution is that when passing the dictionary.Throw().IfContainsKey("key").If{other-methods}(dictionary2); Unless we change all places to accept an I wonder if there is some way around the boxing, or maybe a different solution I'm missing. What do you think? |
@mantinband - Thank you for your deliberate analysis! I tried out two things myself public static ref readonly Validatable<TValue> IfContainsKey<TValue,TDictKey,TDictValue>(this in Validatable<TValue> validatable, TDictKey dictKey)
where TValue : IDictionary<TDictKey,TDictValue>
where TDictKey : notnull and public static ref readonly Validatable<IDictionary<TDictKey, TDictValue>> IfContainsKey<TDictKey, TDictValue>(this in Validatable<IDictionary<TDictKey, TDictValue>> validatable, TDictKey dictKey)
where TDictKey : notnull
{
Validator.ThrowIfContainsKey(validatable.Value, dictKey, validatable.ParamName, validatable.ExceptionCustomizations);
return ref validatable;
} Both do not work because the missing covariant interface. What I do not get is why the implementation for collections does work, as it uses the same strategy: [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref readonly Validatable<TValue> IfContains<TValue, TElement>(
this in Validatable<TValue> validatable,
TElement element)
where TValue : notnull, IEnumerable<TElement?>
where TElement : notnull
{
Validator.ThrowIfContainsElement(
validatable.Value,
element,
validatable.ParamName,
validatable.ExceptionCustomizations);
return ref validatable;
} Even with subclasses of IEnumerable, i.e. List. Why isn't the missing covariant interface a problem here? So after all, I think we need the covariant interface. Regarding your points:
@mantinband: What do you think? Is there another reason for using record structs beside performance benefits? |
@AndreasHoersken first of all thanks for taking the time to think about these issues, I'm happy to have you working with me on this project 🙏🏽
What do you think? |
@mantinband: I think I can learn a lot here, so its my pleasure :-). Thanks again for taking your time to explain things :-). Ad 1.) I would have hoped that, if we understand the "simple case" with one generic param in collections, we could get a simple solution here... I will have another look on that over the weekend. Perhaps this one works because Ad 2.) Benchmark: All in all, it feels a little bit like a case of premature optimization. But then again, I don't know the domain. Ad 3.) Thats interesting. I did not have the Edit: The statement regarding enumerating the whole collections ist not correct. I did not see the pattern matching expression in |
@mantinband : Here are my results:
I added the following results to your tests: I ran a second set of tests, where I removed the usages of
3.) The patternmatching has almost no effect on the structs, whereas the record-implementations perform a little bit worse. Getting back to our originating discussion about the containskey-implementation, I, personally would go with the interface and the record. I think the library will be used if you have a rich feature-set which is easy and concise to use and has only little dependencies. Performance comes second and we can optimize for it when we have real world use cases. But, if you are sure we have to keep the highest performance level in mind, we should only use the boxing / unboxing where it is not possible otherwise as in the dictionary case. @mantinband: What do you think? I will work on the test-implementation a little bit more and share it with #35. e |
Learning a lot here!!! |
Thanks for the benchmarks @AndreasHoersken, will you be able to share the source code? Regarding runtime implications, I agree that for most projects and for the majority of scenarios inside them this optimization is premature and wouldn't have a noticeable impact. That said, I think it is important for the success of the library for the following reasons:
Would love to hear your opinion. I also hope to play around with this in the next couple of days, maybe there is something creative that can be done here that I've missed |
Hi @mantinband, here you can find the code: https://gist.github.com/AndreasHoersken/4de67a3da3a91b5ae6b4f7afe41977fa
|
Why not just write the functionality once for each type, treating public static ref readonly Validatable<TValue> IfContainsKey<TValue, TKey>(
this in Validatable<TValue> validatable,
TKey key,
[CallerArgumentExpression("key")] string? keyParamName = null)
where TValue : IDictionary
where TKey : notnull
{
if (validatable.Value.Contains(key))
{
// throw
}
return ref validatable;
}
public static ref readonly Validatable<TValue> IfContainsKey<TValue, TKey, TDictValue>(
this in Validatable<TValue> validatable,
TKey key,
[CallerArgumentExpression("key")] string? keyParamName = null)
where TValue : IDictionary<TKey, TDictValue>
where TKey : notnull
{
if (validatable.Value.ContainsKey(key))
{
// throw
}
return ref validatable;
} |
@truegoodwill that's probably the best solution here |
Add the following extensions methods for dictionaries:
And the corresponding dictionary properties extension methods:
We don't have dictionary validation yet, so this will hopefully be the start of a bigger feature 🚀
The text was updated successfully, but these errors were encountered: