Replies: 30 comments 1 reply
-
You could just write a deconstructor extension method. public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue val)
{
key = kvp.Key;
val = kvp. Value;
}
//usage:
foreach (var (id, entity) in someDictionary)
{
//....
} |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr With that, you would have to define the names at the point of deconstruction, not when declaring the dictionary. I think that's a pretty big disadvantage. |
Beta Was this translation helpful? Give feedback.
-
C# has no knowledge of the Or are you suggesting some deeper form of naming across generic type arguments? That's kind of already been requested at #829. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour No, this goes further even than generic type arguments, and no, no special knowledge. I want to be able to do this for fields in my own types. SO bad.
|
Beta Was this translation helpful? Give feedback.
-
For a general mechanism, an attribute could be emitted to associate the generic arguments with names. Something like But in this case, somehow the names would need to be pushed down from the |
Beta Was this translation helpful? Give feedback.
-
How does that work where a type might expose two members of that generic type? There's simply no correlation between the generic signature of a type and its shape. Dictionary represents a very niche configuration. |
Beta Was this translation helpful? Give feedback.
-
The first idea that comes to my mind is that you could add another attribute to at most one member (per generic argument) on the class. For example: public class KeyValuePair<TKey, TValue>
{
[GenericArgumentMemberAlias(nameof(TKey))]
public TKey Key;
[GenericArgumentMemberAlias(nameof(TValue))]
public TValue Value;
}
var kvp = new KeyValuePair<string Name, DateTime DateOfBirth>();
var name = kvp.Name; // Translated by compiler into kvp.Key
var dob = kvp.DateOfBirth; // Translated by compiler into kvp.Value This seems like it might become unwieldy pretty quickly, though. I can see that there's some value to be had on |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h I want to be able to do: void Foo(IReadOnlyDictionary<string name, object thing> thingsByName)
{
var x = thingsByName.Where(_ => _.name == "X")...
} (Why not |
Beta Was this translation helpful? Give feedback.
-
One suggestion is as following class Foo1<T>
{
//You can both use the name "Value" and the name given to T
[GenericArgumentMemberName("T")]
public T Value{get;}
}
...
var foo1 = new Foo1<int MyId>();
// Both alternaives is valid.
foo1.Value = 1;
foo1.MyId = 2; And for more advanced example: class MyKeyValue<TKey, TValue>
{
//You can both use the name "Key" and the name given to TKey
[GenericArgumentMemberName("TKey")]
public TKey Key;
//You can both use the name "Value" and the name given to TValue
[GenericArgumentMemberName("TValue")]
public TValue Value;
}
class Foo2<TKey, TValue>
{
//An underlying property that does not necessarily have to have the same typing parameters.
//The first type parameter is given the same name as TKey
//The second type parameter is given the same name as TValue
[GenericArgumentMemberNames("TKey", 0)]
[GenericArgumentMemberNames("TValue", 1)]
public MyKeyValue<string, string> Data = new MyKeyValue<string, string>();
}
...
var foo2 = new Foo2<int MyKey, int MyValue>();
foo2.Data.Key = "3";
foo2.Data.MyKey = "4";
foo2.Data.Value= "5";
foo2.Data.MyValue= "6"; |
Beta Was this translation helpful? Give feedback.
-
You'd then need a way to transfer the argument names between the object, and the items it returns. i.e. an implicit understanding that That means the names have to flow from the generic types, through to the enumerator, and into and out of any LINQ methods which operate over the enumerator. |
Beta Was this translation helpful? Give feedback.
-
In my example, I like the example provided by @yaakov-h as well. |
Beta Was this translation helpful? Give feedback.
-
This would then not work, as Dictionary/IDictionary has no such attributes on it. |
Beta Was this translation helpful? Give feedback.
-
Seems like a lot of compiler chicanery for such limited use cases. You can already easily project the pairs in a dictionary via LINQ to an anonymous type or a named tuple if you really want to work with them that way. |
Beta Was this translation helpful? Give feedback.
-
Much more value for a set of |
Beta Was this translation helpful? Give feedback.
-
I might be wrong, but I thought it is currently understood by the compiler? The reason why it knows |
Beta Was this translation helpful? Give feedback.
-
I think we should add a new |
Beta Was this translation helpful? Give feedback.
-
@Thaina how would that help? |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h To use it in place of |
Beta Was this translation helpful? Give feedback.
-
@Thaina mmhmm, keep going... What is it, how would it work, and how would it solve the issue in this thread using existing language features only? |
Beta Was this translation helpful? Give feedback.
-
I think something like newtypes or easily constructible/deconstructible wrapper types would work much better and enable more use cases: //newtypes
public newtype OrderID : int;
public newtype ItemID : int;
var dictionary = new Dictionary<OrderID, ItemID>() { { 1234, 9876} };
var (orderID, itemID)= dictionary.First(); //KVP has a deconstructor
Debug.WriteLine(orderID); //orderID is of newtype OrderID
Debug.WriteLine(itemID); //itemID is of newtype ItemID //wrappers/records
public struct OrderID(int ID);
public struct ItemID(int ID);
var dictionary = new Dictionary<OrderID, ItemID>() { { 1234, 9876} };
var (order, item) = dictionary.First(); //KVP has a deconstructor
Debug.WriteLine(order.ID);
Debug.WriteLine(item.ID); |
Beta Was this translation helpful? Give feedback.
-
Hi all. If KeyValuePair extended an interface
... and
... that wouldn't break anything would it? And then anyone could make their customised
... and then pass an As a side note, |
Beta Was this translation helpful? Give feedback.
-
@NickRedwood Adding an interface to Also, you seem to be missing a few large pieces, including getting |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h Ok acknowledge retrofitting an interface to Regarding your second point, all existing I suppose my more general point is then, if there is (in future) some mechanism to allow retrofitting of interfaces to other existing interfaces or classes (whether it be default interface implementations, typeclasses, extension interfaces, or something else), either in Core or by the user, then those finer-grained interfaces coupled with that mechanism should (I think) allow this dictionary naming problem to be solved neatly without a new language feature. Do you agree? |
Beta Was this translation helpful? Give feedback.
-
Having custom classes doesn't actually address this issue or any of the points in the OP. You can already write a custom class that implements `IEnumerable<(int itemID, int ownerID)> etc. today. That's not what this issue is about. |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h I realise
Yes, but implementing your own (and yes I went down the wrong path talking about |
Beta Was this translation helpful? Give feedback.
-
@NickRedwood No, the following is perfectly valid. No language changes are required:
|
Beta Was this translation helpful? Give feedback.
-
The custom naming doesn't survive being passed as |
Beta Was this translation helpful? Give feedback.
-
Tuple names also disappear when putting a named tuple like Basically the proposal is to allow consumers of generic types to give names to generic type arguments just like they are allowed for tuple types, and for implementors of generic types to support this feature by passing on these names as aliases for properties (perhaps even other members?) and passing on these names to generic type constructions it itself consumes (like Dictionary<> would do to its KeyValuePair<> instantiations). These names are erased as usual, have no impact on semantics except where used directly in the source code. |
Beta Was this translation helpful? Give feedback.
-
Hello all, |
Beta Was this translation helpful? Give feedback.
-
I just thought about that, but could that be resolved by the role proposal #5497 ? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
When you use a
IDictionary<TKey,TValue>
you only know the type of theTKey
andTValue
. But if the data types are of a simple type likeint
ochstring
, it can be hard to know what that data you should use.Before it was the same problem with
Tuple
, but it is solved in C# 7Below I compare
Dictionary
with theTuple
, both how it was before and how it is in C#7 together with my proposal.Example (before):
Example (proposed):
Ok, it is more common to access the data in a Dictionary by the index property (
dictionary[1234]
), but even then you will benefit from this. I suggest that the popup documentation reflect the name onTKey
andTValue
. The names is directly in the syntax line, and you don't have to read throw the maybe outdated XML documentation (if it is any).This is only a compilation hack (like for the new Tuple) for types that are derived from
IDictionary<TKey,TValue>
.Beta Was this translation helpful? Give feedback.
All reactions