Author Topic: Using the Generic KeyValuePair<>  (Read 7786 times)

0 Members and 1 Guest are viewing this topic.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8702
  • AKA Daniel
Using the Generic KeyValuePair<>
« on: January 14, 2007, 03:20:45 AM »
I thought I might give an example of this. I found this after building my own struct to hold a key pair (Good practice though) .
The built-in KeyValuePair<> struct provides most of the basic methods needed such as:

Code: [Select]
Equals()
GetHashCode()
GetType()
{get, set ;}Key()
ToString()
{get, set ;}Value()

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.Runtime;
  4. //
  5. using AcEd = Autodesk.AutoCAD.EditorInput;
  6. using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
  7.  
  8. [assembly: CommandClass(typeof(MyClassLibrary.CRPClass))]
  9.  
  10. namespace MyClassLibrary
  11. {
  12.   public class CRPClass
  13.   {
  14.     private static short myTypecode;
  15.  
  16.     public CRPClass()
  17.     {
  18.     }
  19.     [CommandMethod("gen")]
  20.     static public void test()
  21.     {
  22.       //
  23.       AcEd.Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  24.  
  25.       //build a list that uses the built-struct KeyValuePair<>;
  26.       List<KeyValuePair<short, object>> myList = new List<KeyValuePair<short, object>>();
  27.       //add some stuff to the list
  28.       myList.Add(new KeyValuePair<short, object>(1000, (object)"Object0"));
  29.       myList.Add(new KeyValuePair<short, object>(1001, (object)"Object1"));
  30.       myList.Add(new KeyValuePair<short, object>(1002, (object)"Object2"));
  31.       myList.Add(new KeyValuePair<short, object>(1003, (object)"Object3"));
  32.       myList.Add(new KeyValuePair<short, object>(1004, (object)"Object4"));
  33.  
  34.       //print the list
  35.       for (int i = 0; i < myList.Count; i++)
  36.       {
  37.         ed.WriteMessage("\n" + myList[i].ToString());
  38.       }
  39.  
  40.       //find using our delegate below
  41.       object Nth1 = nth1(myList, 1001);
  42.       ed.WriteMessage("\n.\nReturn: find 1001 [" + Nth1.ToString() + "]");
  43.  
  44.     }
  45.     //
  46.     internal static object nth1(List<KeyValuePair<short, object>> list, short crpType)
  47.     {
  48.       myTypecode = crpType;
  49.       return (object)list.Find(finder).Value;
  50.     }
  51.     //helper function
  52.     internal static bool finder(KeyValuePair<short, object> i)
  53.     {
  54.       if (i.Key.Equals(myTypecode))
  55.       {
  56.         return true;
  57.       }
  58.       return false;
  59.     }
  60.     //
  61.   }
  62. }
  63.  

Sometimes it pays to look around before rolling your own.

edit:kdub--> code=csharp
« Last Edit: October 01, 2012, 01:00:46 AM by Kerry »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Using the Generic KeyValuePair<>
« Reply #1 on: January 14, 2007, 04:23:30 AM »
That's the one I was after !
Thought about using it for property lists.

Thanks Daniel.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Using the Generic KeyValuePair<>
« Reply #2 on: January 30, 2007, 07:15:19 PM »
Any reason why you didn't use this:

Code: [Select]
Dictionary<short, yourObjectTypeHere> someVar = new Dictionary<short, yourObjectTypeHere>();

...as the Dictionary uses a KeyValuePair anyway to store it's mojo...

Just curious.

Cheers,
Glenn.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8702
  • AKA Daniel
Re: Using the Generic KeyValuePair<>
« Reply #3 on: March 07, 2007, 04:57:04 AM »
Any reason why you didn't use this:

Code: [Select]
Dictionary<short, yourObjectTypeHere> someVar = new Dictionary<short, yourObjectTypeHere>();

...as the Dictionary uses a KeyValuePair anyway to store it's mojo...

Just curious.

Cheers,
Glenn.

Well .. because I’m a tenderfoot and I didn’t see it?
I think I am going to have to roll my own structs anyway, I need to store an association list that’s collected and returned to/from Xdata.

(short)DxfCode.ExtendedDataInteger16
(short)MyKey
(short) DxfCode.ExtendedData…
(object)MyValue

This what I came up with. Any better ideas?


Code - C#: [Select]
  1. public struct XdataStruct
  2.   {
  3.     //
  4.     private short m_xdata1;
  5.     private short m_crptype;
  6.     private short m_xdata2;
  7.     private object m_crpvalue;
  8.     //This is slower Box/UnBox
  9.     public XdataStruct(object[] arrayList)
  10.     {
  11.       if (arrayList == null)
  12.       {
  13.         throw new ArgumentNullException("arrayList");
  14.       }
  15.       else
  16.       {
  17.         m_xdata1 = (short)arrayList[0];
  18.         m_crptype = (short)arrayList[1];
  19.         m_xdata2 = (short)arrayList[2];
  20.         m_crpvalue = (object)arrayList[3];
  21.       }
  22.     }
  23.     public XdataStruct(ArrayList arrayList)
  24.     {
  25.       if (arrayList == null)
  26.       {
  27.         throw new ArgumentNullException("arrayList");
  28.       }
  29.       else
  30.       {
  31.         m_xdata1 = (short)arrayList[0];
  32.         m_crptype = (short)arrayList[1];
  33.         m_xdata2 = (short)arrayList[2];
  34.         m_crpvalue = (object)arrayList[3];
  35.       }
  36.     }
  37.     //This is faster
  38.     public XdataStruct(short extData1, short crpType, short extData2, object crpValue)
  39.     {
  40.       m_xdata1 = extData1;
  41.       m_crptype = crpType;
  42.       m_xdata2 = extData2;
  43.       m_crpvalue = crpValue;
  44.     }
  45.     public short XData1
  46.     {
  47.       get
  48.       {
  49.         return m_xdata1;
  50.       }
  51.       set
  52.       {
  53.         m_xdata1 = value;
  54.       }
  55.     }
  56.     public short CrpType
  57.     {
  58.       get
  59.       {
  60.         return m_crptype;
  61.       }
  62.       set
  63.       {
  64.         m_crptype = value;
  65.       }
  66.     }
  67.     public short XData2
  68.     {
  69.       get
  70.       {
  71.         return m_xdata2;
  72.       }
  73.       set
  74.       {
  75.         m_xdata2 = value;
  76.       }
  77.     }
  78.     public object CrpValue
  79.     {
  80.       get
  81.       {
  82.         return m_crpvalue;
  83.       }
  84.       set
  85.       {
  86.         m_crpvalue = value;
  87.       }
  88.     }
  89.     public static bool operator ==(XdataStruct XdataStructA, XdataStruct XdataStructB)
  90.     {
  91.       return ((((XdataStructA.m_xdata1 == XdataStructB.m_xdata1) &&
  92.                 (XdataStructA.m_crptype == XdataStructB.m_crptype)) &&
  93.                 (XdataStructA.m_xdata2 == XdataStructB.m_xdata2)) &&
  94.                 (XdataStructA.m_crpvalue == XdataStructB.m_crpvalue));
  95.     }
  96.     public static bool operator !=(XdataStruct XdataStructA, XdataStruct XdataStructB)
  97.     {
  98.       return !(XdataStructA == XdataStructB);
  99.     }
  100.     public override bool Equals(object obj)
  101.     {
  102.       if (obj is XdataStruct)
  103.         return this == (XdataStruct)obj;
  104.       else
  105.         return false;
  106.     }
  107.     public override int GetHashCode()
  108.     {
  109.       return base.GetHashCode();
  110.     }
  111.     public string ToString(IFormatProvider provider)
  112.     {
  113.       object[] objArray1 = new object[] { this.m_xdata1, this.m_crptype, this.m_xdata2, this.m_crpvalue };
  114.       return string.Format(provider, "({0},{1},{2},{3})", objArray1);
  115.     }
  116.     public override string ToString()
  117.     {
  118.       return ToString(null);
  119.     }
  120.   }
  121.   #endregion
  122.  

edit:kdub--> code=csharp
« Last Edit: October 01, 2012, 01:01:31 AM by Kerry »

TonyT

  • Guest
Re: Using the Generic KeyValuePair<>
« Reply #4 on: March 09, 2007, 08:36:51 AM »
Hi Dan.

It helps to explore the new classes in .NET 2.0, because
a lot of things have changed with the introduction of
generics (like the Dictionary class, for example).

In the case of XData, the ResultBuffer and TypedValue
objects are the managed storage medium.

One problem there, is that its hard to incrementally build
an array of TypedValue[], because arrays don't allow you
to add elements that easily.

To deal with that, I use something like this:

Code - C#: [Select]
  1.  
  2. public class TypedValueList : List<TypedValue>
  3. {
  4.    public TypedValueList( params TypedValue[] args )
  5.    {
  6.       AddRange( args );
  7.    }
  8.  
  9.    // Make it a bit easier to add items:
  10.  
  11.    public void Add(int typecode, object value)
  12.    {
  13.       base.Add(new TypedValue(typecode, value));
  14.    }
  15.  
  16.    // Implicit conversion to SelectionFilter
  17.    public static implicit operator SelectionFilter( TypedValueList src )
  18.    {
  19.       return src != null ? new SelectionFilter( src ) : null;
  20.    }
  21.  
  22.    // Implicit conversion to ResultBuffer
  23.    public static implicit operator ResultBuffer( TypedValueList src )
  24.    {
  25.       return src != null ? new ResultBuffer( src ) : null;
  26.    }
  27.  
  28.    // Implicit conversion to TypedValue[]
  29.    public static implicit operator TypedValue[]( TypedValueList src )
  30.    {
  31.       return src != null ? src.ToArray() : null;
  32.    }
  33.  
  34.    // Implicit conversion from TypedValue[]
  35.    public static implicit operator TypedValueList( TypedValue[] src )
  36.    {
  37.       return src != null ? new TypedValueList( src ) : null;
  38.    }
  39.  
  40.    // Implicit conversion from SelectionFilter
  41.    public static implicit operator TypedValueList( SelectionFilter src )
  42.    {
  43.       return src != null ? new TypedValueList( src.GetFilter() ) : null;
  44.    }
  45.  
  46.    // Implicit conversion from ResultBuffer
  47.    public static implicit operator TypedValueList( ResultBuffer src )
  48.    {
  49.       return src != null ? new TypedValueList( src.AsArray() ) : null;
  50.    }
  51.  
  52. }
  53.  
  54. // Example:
  55.  
  56.    TypedValueList values = new TypedValueList();
  57.  
  58.    values.Add( 1001, "myappname");
  59.    values.Add( 1040, 99.99 );
  60.    values.Add( 1070, 25);        //......
  61.  
  62.    // a method that takes a result buffer
  63.    public void foo(ResultBuffer buffer)
  64.    {
  65.    }
  66.  
  67.    foo(values);  // can pass a TypedValueList anywhere that
  68.                      // ResultBuffer or SelectionFilter is required
  69.  
  70.    // method that returns a ResultBuffer:
  71.    public ResultBuffer bar()
  72.    {
  73.         return new ResultBuffer(...);  
  74.    }
  75.  
  76.    // Direct assignment from ResultBuffer:
  77.    TypedValueList values = bar();    
  78.  
  79.  

edit:kdub--> code=csharp
« Last Edit: October 01, 2012, 01:01:58 AM by Kerry »

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8702
  • AKA Daniel
Re: Using the Generic KeyValuePair<>
« Reply #5 on: March 09, 2007, 10:04:55 AM »
Wow! Thanks a ton Tony! It seems I am missing a lot of stuff here

I’m using my lisp brain here so I’m probably going about this totally wrong. What I need to do is store an association list like (( 2000 , 724.00)) where 2000 would be my lookup key and 724.00 is the value. I addition to storing my data, I was thinking that I should also store the Xdata type as well, for example ((1070 , 2000 , 1040 , 724.00) (1070 , 2001 , 1071 , 9999)) since my value will be of different types. I probably don’t need to store the first Xdata type since my key will always be an Int16. I was hoping that by storing the Xdata type I wouldn’t have to guess at it later.

 Instead of using the TypedValue struct I thought I would make a new struct “XdataStruct “ that would contain the four items and I would use the List <XdataStruct> collection to store it all.

I could then use List.Find (Predicate<T> match) to retrieve the value I need.

Assuming that I am doing this correctly, my concern is if my struct is too big. I have read that it should be kept at or under 16 bytes. By using 3 Int16s and an Object, I’m exceeding this. I could drop the first short though.

Am I going about this correctly?

Thanks

TonyT

  • Guest
Re: Using the Generic KeyValuePair<>
« Reply #6 on: March 09, 2007, 10:55:26 AM »
Without knowing very much about your particulars, I'd only be
guessing, but the functional equivalent to an association list
in .NET would be the Dictionary<Key,Value> that is, presuming
the Key is unique for each element.

Hence, if your lookup key is an int (or short):

  public class MyDataDictionary : Dictionary<Int16, TypedValue> {}

You can of course, use your own data structure as well, rather
than the TypedValue struct.


Wow! Thanks a ton Tony! It seems I am missing a lot of stuff here

I’m using my lisp brain here so I’m probably going about this totally wrong. What I need to do is store an association list like (( 2000 , 724.00)) where 2000 would be my lookup key and 724.00 is the value. I addition to storing my data, I was thinking that I should also store the Xdata type as well, for example ((1070 , 2000 , 1040 , 724.00) (1070 , 2001 , 1071 , 9999)) since my value will be of different types. I probably don’t need to store the first Xdata type since my key will always be an Int16. I was hoping that by storing the Xdata type I wouldn’t have to guess at it later.

 Instead of using the TypedValue struct I thought I would make a new struct “XdataStruct “ that would contain the four items and I would use the List <XdataStruct> collection to store it all.

I could then use List.Find (Predicate<T> match) to retrieve the value I need.

Assuming that I am doing this correctly, my concern is if my struct is too big. I have read that it should be kept at or under 16 bytes. By using 3 Int16s and an Object, I’m exceeding this. I could drop the first short though.

Am I going about this correctly?

Thanks


It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8702
  • AKA Daniel
Re: Using the Generic KeyValuePair<>
« Reply #7 on: March 10, 2007, 10:19:42 PM »
 public class MyDataDictionary : Dictionary<Int16, TypedValue> {}

Way cool Tony, I think this what I am looking for.
Thanks