In c# I'm a little puzzled to understand Enum.
In my specif case I would need store constant value in a Name Value format like>
300 seconds = 5 minutes
At the moment I use this class.
Would be possible to use Enum instead, so I the Enum class would look likes?
Can I store in an Enum a Pair Values?
Could you provide me a sample of code?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MyWebSite.Models
{
public class Reminders
{
private sortedDictionary<int, string> remindersValue = new SortedDictionary<int, string>();
// We are settign the default values using the Costructor
public Reminders()
{
remindersValue.Add(0, "None");
remindersValue.Add(300, "5 minutes before");
remindersValue.Add(900, "15 minutes before");
}
public SortedDictionary<int, string> GetValues()
{
return remindersValue;
}
}
}
You could use a Tuple<int, int> as dictionary key( at least with .NET >= 4 ).
But since you actually want to store a TimeSpan, use that as key.
private static Dictionary<TimeSpan, string> TimeSpanText = new Dictionary<TimeSpan, string>();
static Reminders()
{
TimeSpanText.Add(TimeSpan.Zero, "None");
TimeSpanText.Add(TimeSpan.FromMinutes( 5 ), "5 minutes before");
TimeSpanText.Add(TimeSpan.FromMinutes( 15 ), "15 minutes before");
TimeSpanText.Add(TimeSpan.FromMinutes( 30 ), "30 minutes before");
TimeSpanText.Add(TimeSpan.FromHours( 1 ), "1 hour before");
// ....
}
public static string DisplayName(TimeSpan ts)
{
string text;
if (TimeSpanText.TryGetValue(ts, out text))
return text;
else
throw new ArgumentException("Invalid Timespan", "ts");
}
You can get the translation in this way:
var quarter = TimeSpan.FromMinutes(15);
string text = TimeSpanText[ quarter ];
You can decorate your enumeration with description attributes and access them later through reflection. For example,
enum ReminderTimes
{
[Description("None")]
None = 0,
[Description("5 minutes before")]
FiveMinutesBefore = 300,
[Description("15 minutes before")]
FifteenMinutesBefore = 900
}
You can get the description by:
public static string GetDescription(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute
= Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
See also: http://www.codeproject.com/Articles/13821/Adding-Descriptions-to-your-Enumerations
An enum is actually a named integer type. E.g.
public enum Foo : int
{
SomeValue = 100,
}
which means that you create a Foo enumeration with the type 'int' and some value. I personally always make this explicit to show what is happening, but c# implicitly makes it the 'int' type (32-bit int).
You can use any name for the enum names and can check if it is a valid enum by using Enum.IsDefined (e.g. to check if 300 is a valid enum name).
update
Okay, actually that's not 100% correct to be honest. This update is just to show what's actually happening under the hood. An enum is a value type with fields that act as names. E.g. the above enum is actually:
public struct Foo
{
private int _value;
public static Foo SomeValue { get { return new Foo() { _value = 100 }; } }
}
Notice that the 'int' is the type of the int (in my case explicit). Because it's a value type, it has the same structure as a real integer in memory - which is probably what's being used by the compiler when you're casting.
If you are asking can you store an integer value against an enum then yes you can e.g.
public enum DurationSeconds
{
None = 0,
FiveMinutesBefore = 300,
FifteenMinutesBefore = 900,
ThirtyMinutesBefore = 1800,
OneHourBefore = 3600,
TwoHoursBefore = 7200,
OneDayBefore = 86400,
TwoDaysBefore = 172800
}
Contrary of what I usually do, I'll add another answer, which is IMO the answer to the problem.
You usually want the compiler to do as much checking as you can before actually using run-time checking. That means in this case using Enum's for getting values:
// provides a strong type when using values in memory to make sure you don't enter incorrect values
public enum TimeSpanEnum : int
{
Minutes30 = 30,
Minutes60 = 60,
}
public class Reminders
{
static Reminders()
{
names.Add(TimeSpanEnum.Minutes30, "30 minutes");
names.Add(TimeSpanEnum.Minutes60, "60 minutes");
}
public Reminders(TimeSpanEnum ts)
{
if (!Enum.IsDefined(typeof(TimeSpanEnum), ts))
{
throw new Exception("Incorrect value given for time difference");
}
}
private TimeSpanEnum value;
private static Dictionary<TimeSpanEnum, string> names = new Dictionary<TimeSpanEnum, string>();
public TimeSpan Difference { get { return TimeSpan.FromSeconds((int)value); } }
public string Name { get { return names[value]; } }
}
When creating the program like this, the language helps you in a couple of ways:
You cannot use timespans that aren't defined
It initializes the dictionary only once, to be exact: when the type is constructed
The Enum.IsDefined makes sure you dont use an incorrect int value (e.g. new Reminders((TimeSpanEnum)5) will fail.
Related
Let me give a simple example for better understanding of question
Library holds:
enum Keys
{
[Description("Color select")]
ColorSelection,
[Description("Day select")]
DaySelection,
[Description("Gender select")]
GenderSelection
}
enum Color
{
[Description("White color")]
White,
[Description("Black color")]
Black,
[Description("Brown color")]
Brown
}
enum Day
{
[Description("Monday")]
Monday,
[Description("Tueday")]
Tuesday,
[Description("Wednesday")]
Wednesday
}
enum Gender
{
[Description("Male gender")]
Male,
[Description("Female gender")]
Female
}
From Client I want like this:
Dictionary<Keys, ??> values = new Dictionary<Keys, ??>();
values.Add(Keys.ColorSelection, <Auto suggest color>);
values.Add(Keys.DaySelection, <Auto suggest day>);
I'm okay to modify the library to have list of values as Enum but, I want the client to auto suggest the values with filters based on the key.
Note:
1. I don't want Class(Model) with property as respective type since there are lot of keys available in the library and client will pick few and provide values.
2. I cannot have values alone as List<Values> since some cases will have same description as value with different key.. Eg: "Yes/No values will be same with different keys"
Any suggestions? Thanks in advance..
You could declare your dictionary as:
var dictionary = new Dictionary<Keys, int>();
And then encapsulate this in your own custom class with a method that uses the Keys value of the key to interpret the value using the corresponding enum.
The whole problem here seems like a code smell though.
I agree with #owen-pauling; I think you should revise your current design. But based on the example you presented, here's one way you can handle this using Dictionary<Keys, int>:
Dictionary<Keys, int> values = new Dictionary<Keys, int>();
values.Add(Keys.ColorSelection, Convert.ToInt32(Color.Black));
values.Add(Keys.GenderSelection, Convert.ToInt32(Gender.Male));
values.Add(Keys.DaySelection, Convert.ToInt32(Day.Wednesday));
foreach (KeyValuePair<Keys, int> kv in values)
{
dynamic enumValue = null;
switch (kv.Key)
{
case Keys.ColorSelection:
enumValue = Enum.Parse(typeof(Color), Convert.ToString(kv.Value));
break;
case Keys.DaySelection:
enumValue = Enum.Parse(typeof(Day), Convert.ToString(kv.Value));
break;
case Keys.GenderSelection:
enumValue = Enum.Parse(typeof(Gender), Convert.ToString(kv.Value));
break;
}
Console.WriteLine(String.Format("Enum value: {0}", enumValue));
}
/* Output:
Enum value: Black
Enum value: Male
Enum value: Wednesday
*/
If you are open to making changes, maybe a class to hold the selections from the client will suffice. Here is an example with List<DetailSelection>:
public class DetailSelection
{
public DetailSelection() { }
public Type SelectionType { get; set; }
public string Description { get; set; }
public int EnumValue { get; set; }
}
List<DetailSelection> details = new List<DetailSelection>();
details.Add(new DetailSelection() {
Description = "Color description",
SelectionType = typeof(Color),
EnumValue = Convert.ToInt32(Color.Black)
});
details.Add(new DetailSelection() {
Description = "Day description",
SelectionType = typeof(Day),
EnumValue = Convert.ToInt32(Day.Wednesday)
});
details.Add(new DetailSelection() {
Description = "Gender description",
SelectionType = typeof(Gender),
EnumValue = Convert.ToInt32(Gender.Male)
});
foreach (var detail in details)
{
var enumValue = Enum.Parse(detail.SelectionType, Convert.ToString(detail.EnumValue));
Console.WriteLine(String.Format("Enum value: {0}", enumValue));
}
/* Output:
Enum value: Black
Enum value: Wednesday
Enum value: Male
*/
In either case, I would probably try to take a step back and re-evaluate your design; just a friendly advice. :-)
I don't think you should use a Dictionary<TKey, TValue> for this; since the key has to be unique, you will be constraining the client to only a single ColorSelection, GenderSelection, DaySelection, etc.
I think the simplest (and probably best) solution is what Milney suggested in a comment:
class Properties
{
Color? ColorSelection { get; set; }
Day? DaySelection { get; set; }
Gender? GenderSelection { get; set; }
}
Client code:
Properties values = new Properties();
values.ColorSelection = < Auto suggest color >;
values.DaySelection = < Auto suggest day >;
However, you seem concerned about having hundreds of properties where only a few of them would have values. This is probably a matter of premature optimization: it feels wasteful, but developer time is worth orders of magnitude more than any memory resources that this approach might cost. However, if that really bothers you, or if you determine through load testing that this is actually a problem, you can optimize your implementations without requiring any change to clients' code:
class Properties
{
private Dictionary<Type, int> values = new Dictionary<Type, int>();
Color? ColorSelection
{
get
{
return values.TryGetValue(typeof(Color), out int i)
? (Color?)i
: null;
}
set
{
values[typeof(Color)] = (int)value;
}
}
...
}
This leaves your API exactly the same, but stores all of the values in a dictionary just like you asked. You can also substitute Type for your Keys enum if you prefer. In fact, you could create a general-purpose "Add" method on your Properties class in case you want to allow client code to programmatically add values based on data known at runtime. But when clients want intellisense suggestions, they can use the properties instead.
If you go this route, I'd suggest using a T4 Template to generate your properties class so you're not writing massive amounts of boilerplate code.
Can I do this ? It doesn't seem so.
public enum Options
{
[Display(Name = string.Format("{0} - {1}","Option One", MyClass.myVariable))]
OptionOne=1,
[Display(Name = string.Format("{0} - {1}","Option Two", MyClass.myVariable))]
OptionTwo=2
}
As opposed to this
public enum Options
{
[Display(Name = "Option 1")]
OptionOne=1,
[Display(Name = "Option 2")]
OptionTwo=2
}
If not, how can I make the Display Name for an enum variable ?
Seems like nobody's dealing with:
If not, how can I make the Display Name for an enum variable ?
I can think about some kind of enum map plus extension method which could work like this:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public enum Foo
{
One = 1,
Two = 2,
}
public static class ExtensionMethods
{
private static readonly Dictionary<Enum, string> s_EnumMap = new Dictionary<Enum, string>
{
{ Foo.One, string.Format("{0} - {1}","Option One", 1) },
{ Foo.Two, string.Format("{0} - {1}","Option Two", 2) }
};
public static String ConvertToString(this Enum eff)
{
return s_EnumMap[eff];
}
}
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
}
}
}
Integers 1 and 2 can be of course replaced by e.g. static variable, such as MyClass.myVariable. If that is the way you would use this code, then keep in mind that s_EnumMap will store the values that MyClass.myVariable variable had at the time when you first used ExtensionMethods class (i.e. when static fields of MyClass were getting initialized). So modifying the code like this:
public MyClass
{
public static int myVariable = 5;
}
public static class ExtensionMethods
{
private static readonly Dictionary<Enum, string> s_EnumMap = new Dictionary<Enum, string>
{
{ Foo.One, string.Format("{0} - {1}","Option One", MyClass.myVariable) },
{ Foo.Two, string.Format("{0} - {1}","Option Two", 2) }
};
public static String ConvertToString(this Enum eff)
{
return s_EnumMap[eff];
}
}
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
MyClass.myVariable = 100;
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
}
}
Would result into:
Option One - 5
Option Two - 2
Option One - 5
Option Two - 2
While after commenting out the first two Console.WriteLines, the output would be:
Option One - 100
Option Two - 2
So if you want to dynamicaly react to changes of MyClass.myVariable then you have to implement some logic to update s_EnumMap`, but as long as I don't know more about the goal you are trying to achieve I cannot provide a better answer.
You could write a separate method to get the display name, or even a small class that has an option member and a display name member. I like Michal's idea better, but since I already started writing this I figured I'd throw it out there!
public enum Option
{
OptionOne = 1,
OptionTwo = 2
}
public static string GetOptionDisplayName(Option option)
{
switch (option)
{
case Option.OptionOne:
return string.Format("{0} - {1}", "Option One", MyClass.MyProperty);
case Option.OptionTwo:
return string.Format("{0} - {1}", "Option Two", MyClass.MyProperty);
default:
return option.ToString();
}
}
public class AnotherOption
{
public Option Option { get; set; }
public string DisplayName
{
get { return GetOptionDisplayName(this.Option); }
}
}
What you want cannot be done. The compiler needs to know the value at compile time.
The short answer no. The value within [Display....] can be known at compile time only. E.g. you can define literals, like string or enum value. string.Format() is called at run time. If possible you should call it in you other logic, using you enum. Or use code generating, e.g. with a tt template
I want to use Data annotations Range attribute inside my mvc viewmodel. Problem is that this range attributes should be dynamic values.
My viewmodel has also ValueOne and ValueTwo properties. Based on this values I want to set Range attr. values like
[Range(1, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
Where 1 and 1000 should be replaces with ValueOne and ValueTwo property values.
so I tried with custom ValidateCustomAttribute
public class ValidateCustomAttribute: ValidationAttribute
{
private readonly double _MinValue = 0;
private readonly double _MaxValue = 100;
public override bool IsValid(object value)
{
double val = (double)value;
return val >= _MinValue && val <= _MaxValue;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessage, _MinValue, _MaxValue);
}
}
how can I replace this
private readonly double _MinValue = 0;
private readonly double _MaxValue = 100;
with dynamic values (ValueOne and ValueTwo from my viewmodel).
This can't be done, you can't have variables in attributes. Attribute values must be known at compile time.
See this question/answer and this one.
Just add a constructor:
private double _MinValue, _MaxValue; // no readonly keyword
public ValidateCustomAttribute(double min, double max, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
_MinValue = min;
_MaxValue = max;
}
What you can't do is have variables in the attribute constructor invokation.
This is not possible:
[ValidateCustom(min, max)]
But if you use literals (or constants) in your code you can have these:
[ValidateCustom(1, 1000)]
And on another class or method:
[ValidateCustom(3, 45)]
What you are missing is the constructor taking in those static values and affixing them to the construct you are describing with your attribute.
EDIT: The ugly way around this
If you really really need this, you can circumvent the limitation but it is as ugly as it can get. I am STRONGLY against this, but you asked for it...
categorize your data
map categories to binding symbols
use binding symbols
resolve binding symbols to data
So, let's get to work:
1) categorize your data
Say, your data is a range (min, max), the first thing to do is establish which values are possible, let's say you have 4 possible ranges (may be hundreds, but that's anther problem altogether).
(1, 1000)
(10, 20)
(3, 45)
(5, 7)
2) map categories to binding symbols
Now you have to use an enum as binding symbols for those ranges:
public enum MyRanges
{
R1, R2, R3, R4
}
3) use binding symbols
Define the constructor as taking in the binding symbol:
private MyRanges _R;
public ValidateCustomAttribute(MyRanges r, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
_R = r;
}
The attribute will be used like this:
[ValidateCustom(MyRanges.R2, "ERROR!")]
4) resolve binding symbols to data
The last you need is a dictionary with the actual data:
Dictionary<MyRanges, double> dataMin = {
{ MyRanges.R1, 1},
{ MyRanges.R2, 10},
{ MyRanges.R3, 3},
{ MyRanges.R4, 5}
};
Dictionary<MyRanges, double> dataMax = {
{ MyRanges.R1, 1000},
{ MyRanges.R2, 20},
{ MyRanges.R3, 45},
{ MyRanges.R4, 7}
};
The test will use the binding this way:
public override bool IsValid(object value)
{
double val = (double)value;
return val >= dataMin[_R] && val <= dataMax[_R]; // get data through binding
}
Now you can change behind the scenes those values and all attributes bound by the binding symbols behave differently:
dataMax[MyRanges.R4] = 29;
Done.
What cannot change is now the binding from attribute to category, but the data contained in the category is free to change.
But ugly and impossible to maintain. Don't do it, really.
You can do it like this:
public class MinimumAgeAttribute : RangeAttribute
{
public static string MinimumValue => ConfigurationManager.AppSettings["your key"];
public static string MaxValue => ConfigurationManager.AppSettings["your key"];
public CustomRangeAttribute(Type type):base(type,MaxValue , MinimumValue)
{
}
}
And after this you have to register the attribute in Global.asax like this:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CustomRangeAttribute),
typeof(RangeAttributeAdapter));
After this you can use it like this:
[CustomRange(typeof(DateTime), ErrorMessage = "You message")]
public DateTime DateOfBirth { get; set; }
I know following syntax is possible with enum, and one can get value by parsing it in int or char.
public enum Animal { Tiger=1, Lion=2 }
public enum Animal { Tiger='T', Lion='L' }
Although following syntax is also right
public enum Anumal { Tiger="TIG", Lion="LIO"}
How do I get the value in this case? If I convert it using ToString(), I get the KEY not the VALUE.
If you really insist on using enum to do this, you can do it by having a Description attribute and getting them via Reflection.
public enum Animal
{
[Description("TIG")]
Tiger,
[Description("LIO")]
Lion
}
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
Then get the value by string description = GetEnumDescription(Animal.Tiger);
Or by using extension methods:
public static class EnumExtensions
{
public static string GetEnumDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
Then use it by string description = Animal.Lion.GetEnumDescription();
You can't use strings in enums. Use one or multiple dictionaries istead:
Dictionary<Animal, String> Deers = new Dictionary<Animal, String>
{
{ Animal.Tiger, "TIG" },
{ ... }
};
Now you can get the string by using:
Console.WriteLine(Deers[Animal.Tiger]);
If your deer numbers are in line ( No gaps and starting at zero: 0, 1, 2, 3, ....) you could also use a array:
String[] Deers = new String[] { "TIG", "LIO" };
And use it this way:
Console.WriteLine(Deers[(int)Animal.Tiger]);
Extension method
If you prefer not writing every time the code above every single time you could also use extension methods:
public static String AsString(this Animal value) => Deers.TryGetValue(value, out Animal result) ? result : null;
or if you use a simple array
public static String AsString(this Animal value)
{
Int32 index = (Int32)value;
return (index > -1 && index < Deers.Length) ? Deers[index] : null;
}
and use it this way:
Animal myAnimal = Animal.Tiger;
Console.WriteLine(myAnimal.AsString());
Other possibilities
Its also possible to do the hole stuff by using reflection, but this depends how your performance should be ( see aiapatag's answer ).
That is not possible, the value of the enum must be mapped to a numeric data type. (char is actually a number wich is wirtten as a letter)
However one solution could be to have aliases with same value such as:
public enum Anumal { Tiger=1, TIG = 1, Lion= 2, LIO=2}
Hope this helps!
This isn't possible with Enums. http://msdn.microsoft.com/de-de/library/sbbt4032(v=vs.80).aspx
You can only parse INT Values back.
I would recommend static members:
public class Animal
{
public static string Tiger="TIG";
public static string Lion="LIO";
}
I think it's easier to handle.
As DonBoitnott said in comment, that should produce compile error. I just tried and it does produce. Enum is int type actually, and since char type is subset of int you can assign 'T' to enum but you cannot assign string to enum.
If you want to print 'T' of some number instead of Tiger, you just need to cast enum to that type.
((char)Animal.Tiger).ToString()
or
((int)Animal.Tiger).ToString()
Possible alternative solution:
public enum SexCode : byte { Male = 77, Female = 70 } // ascii values
after that, you can apply this trategy in your class
class contact {
public SexCode sex {get; set;} // selected from enum
public string sexST { get {((char)sex).ToString();}} // used in code
}
I want to store data such as
{
{"apple",15 }
{"pear",12.5 }
{"", 10 }
{"", 0.45 }
}
Data will be plotted on a bar chart (string will be the legend and double will be the value)
Insert order is important.
Perfs don't matter.
Strings could be duplicated or empty. (values could be duplicated too)
I need to get min and max values (easily if possible) to set the scale.
I use
List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));
Quite boring and unreadable.
Is there a cleaner way to do it ?
StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);
double max = data.values.Max();
double min = data.values.Min();
if not how to get the max value of List<KeyValuePair<string, double>> without too much hassle
NameValueCollection looks nice but its a <string,string> I need a <string,double>
You could create a class like the following:
class X
{
public string Name { get; set; }
public double Value { get; set; }
// name is an optional parameter (this means it can be used only in C# 4)
public X(double value, string name = "")
{
this.Name = name;
this.Value = value;
}
// whatever
}
And then get maximum and minimum values using LINQ with a selector:
var data = new List<X>();
data.Add(new X(35.0, "Apple"))
data.Add(new X(50.0));
double max = data.Max(a => a.Value);
double min = data.Min(a => a.Value);
EDIT: if the code above still seems unreadable to you try to improve it using an operator for cases in which you want to have just the value.
// Inside X class...
public static implicit operator X(double d)
{
return new X(d);
}
// Somewhere else...
data.Add(50.0);
To determine which data structure you really want, lets look at your usage patterns.
Insert order matters.
You don't access your items by key.
You want min and max.
A heap offers min or max, but doesn't preserve order. A hash based dictionary also doesn't preserve order. A List is actually a good choice for your data structure. It is available and offers excellent support.
You can prettify your code by defining classes for both the data structure and your bar data. And you can add min/max functionality to the collection. Note: I didn't use the Linq Min/Max functions, because they return the minimum value, not the minimum element.
public class BarGraphData {
public string Legend { get; set; }
public double Value { get; set; }
}
public class BarGraphDataCollection : List<BarGraphData> {
// add necessary constructors, if any
public BarGraphData Min() {
BarGraphData min = null;
// finds the minmum item
// prefers the item with the lowest index
foreach (BarGraphData item in this) {
if ( min == null )
min = item;
else if ( item.Value < min.Value )
min = item;
}
if ( min == null )
throw new InvalidOperationException("The list is empty.");
return min;
}
public BarGraphData Max() {
// similar implementation as Min
}
}
Have you looked at LookUp?
The only problem is that it's immutable, so you need to be able to create your collection in one go.
As Anthony Pegram notes, it's a bit of a pain to create one. It depends on where your data is coming from. Have a look at the ToLookup method.
If it's worth it for usability (i.e. you're using awkward collections of List<KeyValuePair<string, double>> everywhere, it might just be worth it to implement StringDoubleCollection. It wouldn't be that difficult to wrap the underlying collection with the friendlier syntax you've described in your example.
And, as other comments / answers are suggesting, the Framework doesn't seem to provide a simpler solution that matches all of your requirements...
As for "max value", I assume you mean the Key-Value Pair with the greatest value. It can be retrieved like so:
var max = list.Select(kvp => kvp.Value).Max();
Just define your own model class to hold the data instead of depending on a KeyValuePair and everything becomes cleaner:
using System;
using System.Collections.Generic;
public class Fruit
{
public string Name {get; set;}
public double Price {get; set;}
}
public class Program
{
public static void Main()
{
List<Fruit> _myFruit = new List<Fruit>();
_myFruit.Add(new Fruit{Name="apple", Price=15 });
_myFruit.Add(new Fruit{Name="pear", Price=12.5 });
_myFruit.Add(new Fruit{Name="", Price=10 });
_myFruit.Add(new Fruit{Name="", Price=0.45 });
// etc...
}
}
What about implementing the StringDoubleCollection to work like you want...
public class StringDoubleCollection
{
private List<KeyValuePair<string, double>> myValues;
public List<double> values
{
get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); }
}
public void add(string key, double value)
{
myValues.Add(new KeyValuePair<string,double>(key,value));
}
}
You can implementing Dictionary<key, value>
Dictionary<string, string> openWith = new Dictionary<string, string>();
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
https://learn.microsoft.com/pt-br/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0