Composite Key Dictionary - c#

I have some objects in List, let's say List<MyClass> and MyClass has several properties. I would like to create an index of the list based on 3 properties of of MyClass. In this case 2 of the properties are int's, and one property is a datetime.
Basically I would like to be able to do something like:
Dictionary< CompositeKey , MyClass > MyClassListIndex = Dictionary< CompositeKey , MyClass >();
//Populate dictionary with items from the List<MyClass> MyClassList
MyClass aMyClass = Dicitonary[(keyTripletHere)];
I sometimes create multiple dictionaries on a list to index different properties of the classes it holds. I am not sure how best to handle composite keys though. I considered doing a checksum of the three values but this runs the risk of collisions.

You should use tuples. They are equivalent to a CompositeKey class, but the Equals() and GetHashCode() are already implemented for you.
var myClassIndex = new Dictionary<Tuple<int, bool, string>, MyClass>();
//Populate dictionary with items from the List<MyClass> MyClassList
foreach (var myObj in myClassList)
myClassIndex.Add(Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString), myObj);
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];
Or using System.Linq
var myClassIndex = myClassList.ToDictionary(myObj => Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString));
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];
Unless you need to customize the computation of the hash, it's simpler to use tuples.
If there are a lot of properties you want to include in the composite key, the Tuple type name can become pretty long, but you can make the name shorter by creating your own class deriving from Tuple<...>.
** edited in 2017 **
There is a new option starting with C# 7: the value tuples. The idea is the same, but the syntax is different, lighter:
The type Tuple<int, bool, string> becomes (int, bool, string), and the value Tuple.Create(4, true, "t") becomes (4, true, "t").
With value tuples, it also becomes possible to name the elements. Note that performances are slightly different, so you may want to do some benchmarking if they matter for you.

The best way I could think of is to create a CompositeKey struct and make sure to override the GetHashCode() and Equals() methods in order to ensure speed and accuracy when working with the collection:
class Program
{
static void Main(string[] args)
{
DateTime firstTimestamp = DateTime.Now;
DateTime secondTimestamp = firstTimestamp.AddDays(1);
/* begin composite key dictionary populate */
Dictionary<CompositeKey, string> compositeKeyDictionary = new Dictionary<CompositeKey, string>();
CompositeKey compositeKey1 = new CompositeKey();
compositeKey1.Int1 = 11;
compositeKey1.Int2 = 304;
compositeKey1.DateTime = firstTimestamp;
compositeKeyDictionary[compositeKey1] = "FirstObject";
CompositeKey compositeKey2 = new CompositeKey();
compositeKey2.Int1 = 12;
compositeKey2.Int2 = 9852;
compositeKey2.DateTime = secondTimestamp;
compositeKeyDictionary[compositeKey2] = "SecondObject";
/* end composite key dictionary populate */
/* begin composite key dictionary lookup */
CompositeKey compositeKeyLookup1 = new CompositeKey();
compositeKeyLookup1.Int1 = 11;
compositeKeyLookup1.Int2 = 304;
compositeKeyLookup1.DateTime = firstTimestamp;
Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup1]);
CompositeKey compositeKeyLookup2 = new CompositeKey();
compositeKeyLookup2.Int1 = 12;
compositeKeyLookup2.Int2 = 9852;
compositeKeyLookup2.DateTime = secondTimestamp;
Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup2]);
/* end composite key dictionary lookup */
}
struct CompositeKey
{
public int Int1 { get; set; }
public int Int2 { get; set; }
public DateTime DateTime { get; set; }
public override int GetHashCode()
{
return Int1.GetHashCode() ^ Int2.GetHashCode() ^ DateTime.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is CompositeKey)
{
CompositeKey compositeKey = (CompositeKey)obj;
return ((this.Int1 == compositeKey.Int1) &&
(this.Int2 == compositeKey.Int2) &&
(this.DateTime == compositeKey.DateTime));
}
return false;
}
}
}
An MSDN article on GetHashCode():
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

How about Dictionary<int, Dictionary<int, Dictionary<DateTime, MyClass>>>?
This would allow you to do:
MyClass item = MyData[8][23923][date];

You can store them in a struct and use that as the key:
struct CompositeKey
{
public int value1;
public int value2;
public DateTime value3;
}
Link to get hash code:
http://msdn.microsoft.com/en-us/library/system.valuetype.gethashcode.aspx

Now that VS2017/C#7 has come out, the best answer is to use ValueTuple:
// declare:
Dictionary<(string, string, int), MyClass> index;
// populate:
foreach (var m in myClassList) {
index[(m.Name, m.Path, m.JobId)] = m;
}
// retrieve:
var aMyClass = index[("foo", "bar", 15)];
I chose to declare the dictionary with an anonymous ValueTuple (string, string, int). But I could have given them names (string name, string path, int id).
Perfwise, the new ValueTuple is faster than Tuple at GetHashCode but slower at Equals. I think you'd need to do complete end-to-end experiments to figure out which is really fastest for your scenario. But the end-to-end niceness and language syntax for ValueTuple makes it win out.
// Perf from https://gist.github.com/ljw1004/61bc96700d0b03c17cf83dbb51437a69
//
// Tuple ValueTuple KeyValuePair
// Allocation: 160 100 110
// Argument: 75 80 80
// Return: 75 210 210
// Load: 160 170 320
// GetHashCode: 820 420 2700
// Equals: 280 470 6800

Two approaches immediately spring to mind:
Do as Kevin suggested and write a struct that will serve as your key. Be sure to make this struct implement IEquatable<TKey> and to override its Equals and GetHashCode methods*.
Write a class that utilizes nested dictionaries internally. Something like: TripleKeyDictionary<TKey1, TKey2, TKey3, TValue>... this class would internally have a member of type Dictionary<TKey1, Dictionary<TKey2, Dictionary<TKey3, TValue>>>, and would expose methods such as this[TKey1 k1, TKey2 k2, TKey3 k3], ContainsKeys(TKey1 k1, TKey2 k2, TKey3 k3), etc.
*A word on whether overriding the Equals method is necessary: while it's true that the Equals method for a struct compares the value of each member by default, it does so by using reflection -- which inherently entails performance costs -- and is therefore not a very appropriate implementation for something that is meant to be used as a key in a dictionary (in my opinion, anyway). According to the MSDN documentation on ValueType.Equals:
The default implementation of the
Equals method uses reflection to
compare the corresponding fields of
obj and this instance. Override the
Equals method for a particular type to
improve the performance of the method
and more closely represent the concept
of equality for the type.

If the key is part of the class then use KeyedCollection.
It is a Dictionary where the key is derived from the object.
Under the covers it is Dictionary
Don't have to repeat the key in the Key and Value.
Why take a chance the key is not the same in the Key as the Value.
Don't have to duplicate the same information in memory.
KeyedCollection Class
Indexer to expose the composite key
using System.Collections.ObjectModel;
namespace IntIntKeyedCollection
{
class Program
{
static void Main(string[] args)
{
Int32Int32DateO iid1 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
Int32Int32DateO iid2 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
if (iid1 == iid2) Console.WriteLine("same");
if (iid1.Equals(iid2)) Console.WriteLine("equals");
// that are equal but not the same I don't override = so I have both features
Int32Int32DateCollection int32Int32DateCollection = new Int32Int32DateCollection();
// dont't have to repeat the key like Dictionary
int32Int32DateCollection.Add(new Int32Int32DateO(0, 0, new DateTime(2008, 5, 1, 8, 30, 52)));
int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
int32Int32DateCollection.Add(iid1);
//this would thow a duplicate key error
//int32Int32DateCollection.Add(iid2);
//this would thow a duplicate key error
//int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
Console.WriteLine("count");
Console.WriteLine(int32Int32DateCollection.Count.ToString());
// reference by ordinal postion (note the is not the long key)
Console.WriteLine("oridinal");
Console.WriteLine(int32Int32DateCollection[0].GetHashCode().ToString());
// reference by index
Console.WriteLine("index");
Console.WriteLine(int32Int32DateCollection[0, 1, new DateTime(2008, 6, 1, 8, 30, 52)].GetHashCode().ToString());
Console.WriteLine("foreach");
foreach (Int32Int32DateO iio in int32Int32DateCollection)
{
Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
}
Console.WriteLine("sorted by date");
foreach (Int32Int32DateO iio in int32Int32DateCollection.OrderBy(x => x.Date1).ThenBy(x => x.Int1).ThenBy(x => x.Int2))
{
Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
}
Console.ReadLine();
}
public class Int32Int32DateCollection : KeyedCollection<Int32Int32DateS, Int32Int32DateO>
{
// This parameterless constructor calls the base class constructor
// that specifies a dictionary threshold of 0, so that the internal
// dictionary is created as soon as an item is added to the
// collection.
//
public Int32Int32DateCollection() : base(null, 0) { }
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items.
//
protected override Int32Int32DateS GetKeyForItem(Int32Int32DateO item)
{
// In this example, the key is the part number.
return item.Int32Int32Date;
}
// indexer
public Int32Int32DateO this[Int32 Int1, Int32 Int2, DateTime Date1]
{
get { return this[new Int32Int32DateS(Int1, Int2, Date1)]; }
}
}
public struct Int32Int32DateS
{ // required as KeyCollection Key must be a single item
// but you don't really need to interact with Int32Int32DateS directly
public readonly Int32 Int1, Int2;
public readonly DateTime Date1;
public Int32Int32DateS(Int32 int1, Int32 int2, DateTime date1)
{ this.Int1 = int1; this.Int2 = int2; this.Date1 = date1; }
}
public class Int32Int32DateO : Object
{
// implement other properties
public Int32Int32DateS Int32Int32Date { get; private set; }
public Int32 Int1 { get { return Int32Int32Date.Int1; } }
public Int32 Int2 { get { return Int32Int32Date.Int2; } }
public DateTime Date1 { get { return Int32Int32Date.Date1; } }
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || !(obj is Int32Int32DateO)) return false;
Int32Int32DateO item = (Int32Int32DateO)obj;
return (this.Int32Int32Date.Int1 == item.Int32Int32Date.Int1 &&
this.Int32Int32Date.Int2 == item.Int32Int32Date.Int2 &&
this.Int32Int32Date.Date1 == item.Int32Int32Date.Date1);
}
public override int GetHashCode()
{
return (((Int64)Int32Int32Date.Int1 << 32) + Int32Int32Date.Int2).GetHashCode() ^ Int32Int32Date.GetHashCode();
}
public Int32Int32DateO(Int32 Int1, Int32 Int2, DateTime Date1)
{
Int32Int32DateS int32Int32Date = new Int32Int32DateS(Int1, Int2, Date1);
this.Int32Int32Date = int32Int32Date;
}
}
}
}
As for using value type fpr the key Microsoft specifically recommends against it.
ValueType.GetHashCode
Tuple is technically not a value type but suffers from the same symptom (hash collisions) and is not good candidate for a key.

May I suggest an alternative - a anonymous object. It's the same we use in GroupBy LINQ method with multiple keys.
var dictionary = new Dictionary<object, string> ();
dictionary[new { a = 1, b = 2 }] = "value";
It may looks strange, but I've benchmarked Tuple.GetHashCode and new{ a = 1, b = 2 }.GetHashCode methods and the anonymous objects wins on my machine on .NET 4.5.1:
Object - 89,1732 ms for 10000 calls in 1000 cycles
Tuple - 738,4475 ms for 10000 calls in 1000 cycles

Another solution to the ones already mentioned would be to store some kind of list of all keys generated so far and when a new object is generated you generate it's hashcode (just as a starting point), check if it's already in the list, if it is, then add some random value etc to it until you've got a unique key, then store that key in the object itself and in the list and return that as the key at all times.

As an alternative:
Maybe this will help somebody with this necessity.
One option would be to use strings as a Composite Key for the dictionary. Example:
var myDict = new Dictionary<string, bool>();
myDict.Add($"{1}-{1111}-{true}", true);
myDict.Add($"{1}-{1111}-{false}", false);
This way you can store keys with any format. If you want you can always define a function that builds your key as this:
string BuildKey(int number, string name, bool disabled) => $"{number}-{name}-{disabled}";

Related

Why the tuple-type list element's value cannot be modified?

In C# 8.0, I can modify the value inside a tuple directly by accessing the field name:
(string name, int score) student = ("Tom", 100);
student.name = "Jack";
Console.WriteLine(student);
And I can modify the list element's property as follow:
var list = new List<Student>(); // assume I have a Student class which has a Name property
list.Add(new Student { Name = "Tom" });
list[0].Name = "Jack";
Console.WriteLine(list[0]);
But why can't I modify the tuple-type element's value like this?
var list = new List<(string name, int score)>();
list.Add(("Tom", 100));
list[0].name = "Jack"; // Error!
Console.WriteLine(list[0]);
A tuple (ValueTuple) is a struct. Rather than returning a reference to the value as is the case with your Student example, you would actually recieve a copy of the tuple.
Changes to that copy wouldn't be reflected in the list and would be discarded. The compiler is smart enough to recognize this and stops you from doing it.
If it did compile, it would be to something similar to the following:
var list = new List<(string name, int score)>(); list.Add(("Tom", 100));
var copy = list[0];
copy.name = "Jack";
Console.WriteLine(copy.name); // Jack
Console.WriteLine(list[0].name); // still Tom
Mutable structs can be dangerous if you don't use them properly. The compiler is simply doing its job.
You can work around this with the following:
var list = new List<(string name, int score)>(); list.Add(("Tom", 100));
var copy = list[0];
copy.name = "Jack";
list[0] = copy; // put it back
Console.WriteLine(copy.name); // Jack
Console.WriteLine(list[0].name); // Jack
Try It Online
If you use an array (string, int)[] instead of a List<(string, int)>, this isn't a problem due to the way array element access works:
var arr = new (string name, int score) [] { ( "Tom", 10 ) };
arr[0].name = "Jack";
Console.WriteLine(arr[0].name); // Jack
Try It Online
This behavior is not unique to List or your tuple type. You'll experience this issue with any collection where the element is a Value Type (unless of course they offer a ref element accessor).
Note that there are similar issues when having a readonly field of a mutable value type that mutates via method calls. This can be much more insidious as no error or warning is emitted:
struct MutableStruct {
public int Val;
public void Mutate(int newVal) {
Val = newVal;
}
}
class Test {
private readonly MutableStruct msReadonly;
private MutableStruct msNormal;
public Test() {
msNormal = msReadonly = new MutableStruct(){ Val=5 };
}
public void MutateReadonly() {
Console.WriteLine(msReadonly.Val); // 5
msReadonly.Mutate(66); // defensive copy!
Console.WriteLine(msReadonly.Val); // still 5!!!
}
public void MutateNormal() {
Console.WriteLine(msNormal.Val); // 5
msNormal.Mutate(66);
Console.WriteLine(msNormal.Val); // 66
}
}
new Test().MutateReadonly();
new Test().MutateNormal();
Try It Online
ValueTuple is a great addition to the framework and language. But there's a reason you'll often hear that [Mutable] structs are evil. In the majority of cases you shouldn't hit these restrictions. If you find yourself falling into this pattern a lot, I suggest moving over to a record, which is a reference type (thus not suffering these issues) and can be reduced to a tuple-like syntax.
Mutable value types are evil, it's hard to see why this prints "Tom" not "Jack":
(string name, int score) student = ("Tom", 100);
(string name, int score) student2 = student;
student.name = "Jack";
Console.WriteLine(student2);
The reason is that you always create a copy. Because it's not obvious you should avoid mutable value types. To avoid that people will fall into that trap the compiler just allows to modify the object directly via properties(like above). But if you try to do it via a method call you get a compiler error "Cannot modify the return value of ... because it is not a variable".
So this is not allowed:
list[0].name = "Jack";
It would create a new copy of the ValueTuple, assigns a value but doesn't use or store it anywhere.
This compiles because you assign it to a new variable and modify it via property:
(string name, int score) x = list[0];
x.name = "Jack"; // Compiles
So it compiles but gives you again a suprising result:
Console.WriteLine(list[0]); // Tom
Read more about it here: Do Not Define Mutable Value Types

C# Compare two object values

I currently have two objects (of the same type) that may represent any primitive value such as string, int, datetime etc.
var valueX = ...;
var valueY = ...;
Atm I compare them on string level like this
var result = string.Compare(fieldValueX.ToString(), fieldValueY.ToString(), StringComparison.Ordinal);
But I need to compare them on type level (as ints if those happen to be ints
int i = 0;
int j = 2;
i.CompareTo(j);
, as dates if they happen to be date etc), something like
object.Compare(x,y);
That returns -1,0,1 in the same way. What are the ways to achieve that ?
Thanks for your answers, the correct way was to check if the object implements IComparable and if it does - make a typecast and call CompareTo
if (valueX is IComparable)
{
var compareResult = ((IComparable)valueX).CompareTo((IComparable)valueY);
}
Object1.Equals(obj1, obj2) wont work unless #object is referencing the same object.
EG:
var obj1 = new MyObject();
var obj2 = new MyObject();
This will return "False" for Object1.Equals(obj1, obj2) as they are different ref's
var obj1 = new MyObject();
var obj2 = obj1;
This will return "True" for Object1.Equals(obj1, obj2) as they are the same ref.
Solution:
You will most likely need to write an extension method that overrides Object.Equals. either create a custom object comparer for a specific type (See here for custom object comparer:) or you can dynamically go through each property and compare.
There's several options to do this.
Override Object.Equal
You can override the Object.Equal() method in the class, and then determine what makes the objects equal there. This can also let you cleverly decide what to compare, since it appears those objects can be multiple data types. Inside this override, you'll need to handle each possible case. You can read more about this option here:
https://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx
It should be noted by default, Object.Equal() will compare your objects references.
Implement IComparable
IComparable is a neat interface that gives an object Compare. As the comments mention, this will let you define how to compare the objects based on whatever criteria you want.
This option gets covered here: https://msdn.microsoft.com/en-us/library/system.icomparable(v=vs.110).aspx
Implement CompareBy() Methods
Alternatively, you can implement methods for each possible type, ie CompareByInt() or CompareByString(), but this method depends on you knowing what you're going to have when you go to do it. This will also have the negative effect of making code more difficult to maintain, as there's many more methods involved.
You can write a GeneralComparer with a Compare method, overloaded as necessary.
For types that must perform a standard comparison you can use EqualityComparer<T>.Default; for other types you write your own comparison function. Here's a sample:
static class GeneralComparer
{
public static int Compare(int x, int y)
{
//for int, use the standard comparison:
return EqualityComparer<int>.Default.Equals(x, y);
}
public static int Compare(string x, string y)
{
//for string, use custom comparison:
return string.Compare(x, y, StringComparison.Ordinal);
}
//overload for DateTime
//overload for MyType
//overload for object
//...
}
The correct overload is chosen at runtime.
There's a drawback: if you declare two int (or other specific types) as object, the object overload is called:
object a = 2;
object b = 3;
//this will call the "Compare(object x, object y)" overload!
int comparison = GeneralComparer.Compare(a, b);
converting the objects to dictionary, then following math set(s) concept subtract them, result items should be empty in case they are identically.
public static IDictionary<string, object> ToDictionary(this object source)
{
var fields = source.GetType().GetFields(
BindingFlags.GetField |
BindingFlags.Public |
BindingFlags.Instance).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source) ?? string.Empty
);
var properties = source.GetType().GetProperties(
BindingFlags.GetField |
BindingFlags.GetProperty |
BindingFlags.Public |
BindingFlags.Instance).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null) ?? string.Empty
);
return fields.Concat(properties).ToDictionary(key => key.Key, value => value.Value); ;
}
public static bool EqualsByValue(this object source, object destination)
{
var firstDic = source.ToFlattenDictionary();
var secondDic = destination.ToFlattenDictionary();
if (firstDic.Count != secondDic.Count)
return false;
if (firstDic.Keys.Except(secondDic.Keys).Any())
return false;
if (secondDic.Keys.Except(firstDic.Keys).Any())
return false;
return firstDic.All(pair =>
pair.Value.ToString().Equals(secondDic[pair.Key].ToString())
);
}
public static bool IsAnonymousType(this object instance)
{
if (instance == null)
return false;
return instance.GetType().Namespace == null;
}
public static IDictionary<string, object> ToFlattenDictionary(this object source, string parentPropertyKey = null, IDictionary<string, object> parentPropertyValue = null)
{
var propsDic = parentPropertyValue ?? new Dictionary<string, object>();
foreach (var item in source.ToDictionary())
{
var key = string.IsNullOrEmpty(parentPropertyKey) ? item.Key : $"{parentPropertyKey}.{item.Key}";
if (item.Value.IsAnonymousType())
return item.Value.ToFlattenDictionary(key, propsDic);
else
propsDic.Add(key, item.Value);
}
return propsDic;
}
originalObj.EqualsByValue(messageBody); // will compare values.
source of the code

displaying structs in an array using enumerator

In an object I have :
public IEnumerable<voiture> recup_voitures()
{
foreach (voiture v in _arrVCollection)
{
yield return (v);
}
}
voiture being a struct and _arrVCollection being an array containing some struct voiture.
In my main class I have :
foreach (CarCollection.voiture o in collection.recup_voitures())
{
//some code to display the content of each struct
}
What is happening is that if I have an array of length 5 and only 1 struct voiture in it, it will do the displaying code 5 times instead of only 1. What am I doing wrong?
If you are creating array of struct with length, say 5, it means array will contain 5 structs constructed using default constructor.
voiture[] arr = new voiture[5];
arr[0] = some_non-default_voiture;
In that case your array will contain one non-default voiture instance and four default instances.
To get only one voiture instance you can create array with length 1, or use List<T>:
List<voiture> = new List<voiture> { new voiture() };
If you really need to deal with array with length 5, consider to use nullable types:
voiture?[] _arrVCollection = new voiture?[5];
_arrVCollection[0] = new voiture();
And enumerate like this:
public IEnumerable<voiture> recup_voitures()
{
foreach (voiture? v in _arrVCollection)
{ if (v.HasValue)
yield return v.Value;
}
}
Edit:
As Servy mentioned, method recup_voitures() can be rewritten with linq:
public IEnumerable<voiture> recup_voitures()
{
return _arrVCollection.Where(x => x.HasValue).Select(x => x.Value);
}
In your current code you get exception.
You can change your code in recup_voitures methods if the voiture will be class:
public static IEnumerable<voiture> recup_voitures()
{
foreach (voiture v in _arrVCollection)
{
if (v != null)
yield return (v);
}
}

Better writing of a static Dictionary

I am keeping a static dictionary to map a simple integer stored in a database to an enum value.
static Dictionary<long, EModelType> AttributeIdTypeToEModelType =
new Dictionary<long, EModelType>()
{
{1, EModelType.StatStr},
{6, EModelType.HistStr},
{7, EModelType.HistVal}
};
The great advantage is that I use it to directly get my enum value as the data arrive from the database.
typ = AttributeIdTypeToEModelType[i];
The usage of this system is neat, but it doesn't look clean to me to have a static dictionary just for this.
I had no chance trying to find a cleaner way to use enumerators and overriding their values.
Any advice?
You don't need a Dictionary to cast an int to the appropriate Enum type:
var type = (EModelType)yourInt;
or using Enum.ToObject:
var type = Enum.ToObject(typeof(EModelType) , yourInt);
and you can check that it exists with Enum.IsDefined:
if (! Enum.IsDefined(typeof(EModelType), yourInt)) throw new ArgumentException("Illegal type");
If the value in the database is a string, then use:
EnumType x = (EnumType)Enum.Parse(typeof(EnumType), dr[0].ToString());
If the value in the database is a long, then use:
EnumType x = (EnumType)dr[0];
If you need the long value of an enum, use:
long x = (long)EnumType.SomeEnum
You should define your enum with an int backing type, like this:
public enum EModelType : int
{
StatStr = 1,
HistStr = 6,
HistVal = 7
}
Then, like Tim and Chris suggested, just cast or parse the integer from the database to your enum type.

Autovivification in C#

Trying to wrap my head around perl's Autovivification and based on what it sounds like, It seems to work similar to dynamics in C# as a dynamic object is not assigned a type until runtime or, am I totally off here. If so then is there a comparable idea that I can bridge off of in C# that makes sense?
Edit
Okay so I'm apparently way off. So as second part of the 2 part question, is there anything conceptually comparable in C#? To be clear I'm looking for a concept in C# that is comparable to Autovivification. Doesn't have to be exactly the same but close enough conceptually to make sense. And as I stated eariler I am by no means a perl hacker or python hacker by any stretch of the imagination but, I am familar with c based languages C, C++, C#, java, javascript. I was thinking of C#'s dynamics but, as of right now I'm thinking lazy loading based on the info here if that helps....
I can't speak to C#, but in layman's terms, Perl's autovivification is the process of creating a container object out of an undefined value as soon as it is needed.
Despite most of Perl being quite dynamic, Perl's dereferencing syntax unambiguously specifies the type of the reference at compile time. This allows the interpreter to know what it needs out of a variable before the variable is ever defined.
my $var; # undefined
# to autovivify to an array:
#$var = 1..5; # # here implies ARRAY
$$var[4] = 5; # square brackets imply ARRAY
$#$var; # $# implies ARRAY (returns the last index number)
# to autovivify to a hash:
%$var = (a => 1); # % implies HASH
$$var{asdf} = 5; # curly braces imply HASH
This list could be longer, but should give you an idea.
So basically, when you have a line like this:
my $var;
$var->[1]{x}[3]{asdf}
Perl looks on the right side of the -> and sees square braces. This means that the invocant $var must be an array reference. Since the invocant is undefined, Perl creates a new array and installs its reference into $var. This same process is then repeated for every subsequent dereferencing.
So the line above really means:
(((($var //= [])->[1] //= {})->{x} //= [])->[3] //= {})->{asdf};
which is fairly hideous, and hence autovivification. (//= is the defined-or assignment operator in perl 5.10+)
Update:
As per cjm's comment, to put this into general non-perl terms, to achieve autovivification in another language, you need a lazy object that supports indexing via [...] and {...}. When either of these indexing operations are performed, the object replaces itself with either an array or hash. Every time the object is then accessed, if the cell is empty, it should return another lazy object.
obj = new lazy_obj()
level1 = obj[4] # sets obj to be an array, returns a new lazy_obj for level1
level2 = level1{asdf} # sets level1 (and obj[4]) to a hash,
# returns a new lazy_obj for level2
So basically you need two things, the ability to create an object that supports indexing with both array and hash subscripts (or the equivalent), and a mechanism such that an object can replace itself in memory with another object (or that can lock itself to one interpretation, and then store the new object internally.
Something like the following pseudo-code could be a start:
class autoviv {
private var content;
method array_subscript (idx) {
if (!content) {
content = new Array();
}
if (typeof content == Array) {
if (exists content[idx]) return content[idx];
return content[idx] = new autoviv();
} else {
throw error
}
}
method hash_subscript (idx) {
if (!content) {
content = new Hash();
}
if (typeof content == Hash) {
if (exists content{idx}) return content{idx};
return content{idx} = new autoviv();
} else {
throw error
}
}
// overload all other access to return undefined, so that the value
// still looks empty for code like:
//
// var auto = new autoviv();
// if (typeof auto[4] == autoviv) {should run}
// if (auto[4]) {should not run}
}
Uri Guttman's autovivification tutorial might be of some use.
Basically, it is the ability of hitherto untouched aggregates and members of aggregates to spring to life upon first use.
For example, I can do this:
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;
my #dummy;
push #{ $dummy[0] }, split ' ', 'this that and the other';
push #{ $dummy[1] }, { qw(a b c d) };
print Dumper \#dummy;
Neither $dummy[0] nor $dummy[1] exist before they are dereferenced.
Now, if you are willing to forgo strict (which, you shouldn't be), you can also do things like:
use Data::Dumper;
#$x = qw(a b c d);
print Dumper $x;
whereby the undefined variable $x becomes an array reference because it is being dereferenced as such.
You can implement autovification-like behavior with creating say, an IDictionary<X,Y> that returns (and stores) a new IDictionary<X,Y> (e.g. recursively the same type) when a [] to an unset key occurs. This approach is used in Ruby to great success (an example) -- however, it's really not so useful in a statically typed language because there is no way to "get to" the leaf values cleanly -- at least in context of most existing contracts such as an IDictionary.
With the advent of dynamic, this may be possible in C# to do sanely, but I do not know.
How about something like this for a simple implementation of auto-vivification like behaviour of a Dictionary in C#? Obviously this doesn't handle it in the generic way that Perl does, but I believe that it has the same effect.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// The purpose of this class is to provide a dictionary with auto-vivification behaviour similar to Perl's
// Using dict[index] will succeed regardless of whether index exists in the dictionary or not.
// A default value can be set to be used as an initial value when the key doesn't exist in the dictionary
namespace XMLTest
{
class AutoDictionary<TKey,TValue> : Dictionary<TKey,TValue> {
Object DefaultValue ;
public AutoDictionary(Object DefaultValue) {
this.DefaultValue = DefaultValue;
}
public AutoDictionary() {
this.DefaultValue = null;
}
public new TValue this[TKey index] {
get {
try {
return base[index];
}
catch (KeyNotFoundException) {
base.Add(index, (TValue)DefaultValue);
return (TValue)DefaultValue ;
}
}
set {
try {
base[index] = value ;
}
catch (KeyNotFoundException) {
base.Add(index, value);
}
}
}
}
}
I would recommend using extension methods instead of inheritance.
e.g.:
namespace DictionaryEx
{
public static class Ex
{
public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key)
{
var value = default(TV);
if (dict.TryGetValue(key, out value))
{
return value;
}
value = default(TV);
dict[key] = value;
return value;
}
public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue)
{
TV value;
if (dict.TryGetValue(key, out value))
{
return value;
}
dict[key] = defaultValue;
return defaultValue;
}
public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key, Func<TV> valueFactory)
{
TV value;
if (dict.TryGetValue(key, out value))
{
return value;
}
value = valueFactory();
dict[key] = value;
return value;
}
}
}
Using indexers and C# 4.0 dynamics,
class Tree
{
private IDictionary<string, object> dict = new Dictionary<string, object>();
public dynamic this[string key]
{
get { return dict.ContainsKey(key) ? dict[key] : dict[key] = new Tree(); }
set { dict[key] = value; }
}
}
// Test:
var t = new Tree();
t["first"]["second"]["third"] = "text";
Console.WriteLine(t["first"]["second"]["third"]);
DynamicObject can be used for implementing different syntaxes also,
using System;
using System.Collections.Generic;
using System.Dynamic;
class Tree : DynamicObject
{
private IDictionary<object, object> dict = new Dictionary<object, object>();
// for t.first.second.third syntax
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var key = binder.Name;
if (dict.ContainsKey(key))
result = dict[key];
else
dict[key] = result = new Tree();
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dict[binder.Name] = value;
return true;
}
// for t["first"]["second"]["third"] syntax
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
var key = indexes[0];
if (dict.ContainsKey(key))
result = dict[key];
else
dict[key] = result = new Tree();
return true;
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
dict[indexes[0]] = value;
return true;
}
}
// Test:
dynamic t = new Tree();
t.first.second.third = "text";
Console.WriteLine(t.first.second.third);
// or,
dynamic t = new Tree();
t["first"]["second"]["third"] = "text";
Console.WriteLine(t["first"]["second"]["third"]);

Categories