Author Topic: Generic Dictionary  (Read 14713 times)

0 Members and 1 Guest are viewing this topic.

cadpro

  • Guest
Generic Dictionary
« on: July 21, 2011, 10:56:30 AM »
Hi,

Is it possible to add a Generic .NET Dictionary to an XRecord, or convert a .NET Dictionary to DBDictionary?

Thanks

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Generic Dictionary
« Reply #1 on: July 21, 2011, 11:52:08 AM »
Can't do the first (but you *can* add a soft or hard pointer to another Extension Dictionary in the XRecord), but the second could be done with a bit of work, depending on whats in the Dictionary object.  You could map each entry in the Dictionary into a separate Extension Dictionary with the contents stored in a single XRecord, or you could use a single Extension Dictionary with multiple XRecords, or even a single Extension Dictionary with a single XRecord with multiple DXF content.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

cadpro

  • Guest
Re: Generic Dictionary
« Reply #2 on: July 21, 2011, 12:04:14 PM »
Hi,

Thanks for the reply.

The Generic Dictionary contains a Key of string datatype and the Value is a String Array. Could you give me some example code on how to map this to the Xrecord.

Thanks

kaefer

  • Guest
Re: Generic Dictionary
« Reply #3 on: July 21, 2011, 12:15:01 PM »
Can't do the first (but you *can* add a soft or hard pointer to another Extension Dictionary in the XRecord), but the second could be done with a bit of work, depending on whats in the Dictionary object.  You could map each entry in the Dictionary into a separate Extension Dictionary with the contents stored in a single XRecord, or you could use a single Extension Dictionary with multiple XRecords, or even a single Extension Dictionary with a single XRecord with multiple DXF content.

Those suggestions are very cool, there's only a bit of background necessary to explain why:

AutoCAD's internal data structures traditionally predate .NET generics, so they implement the non-generic variety of IDictionary and IEnumerable for DBDictionary. That means they're either stuck with boxed objects -- cf. IDictionary.Add(object key, object value) --, or they declare which concrete data types to use, which are string and ObjectId here. Since you can do reverse look-up with the NameAt method, either Dictionary<string,ObjectId> or Dictionary<ObjectId,string> could be mapped in a one-on-one fashion to a DBDictionary.

cadpro

  • Guest
Re: Generic Dictionary
« Reply #4 on: July 21, 2011, 12:44:39 PM »
Since you can do reverse look-up with the NameAt method, either Dictionary<string,ObjectId> or Dictionary<ObjectId,string> could be mapped in a one-on-one fashion to a DBDictionary.

Please can I get some sample code?

Thanks

kaefer

  • Guest
Re: Generic Dictionary
« Reply #5 on: July 21, 2011, 12:51:03 PM »
Please can I get some sample code?

Code: [Select]
    let db = HostApplicationServices.WorkingDatabase
    use tr = db.TransactionManager.StartTransaction()
   
    let key = "xyz"
    let strings = [| "foo"; "bar"; "fred" |]
   
    let lt = tr.GetObject(db.LayerTableId, OpenMode.ForWrite) :?> LayerTable
    if lt.ExtensionDictionary.IsNull then
        lt.CreateExtensionDictionary()
    let ext = tr.GetObject(lt.ExtensionDictionary, OpenMode.ForWrite) :?> DBDictionary
    let tvs =
        strings |> Array.map (fun s ->
            new TypedValue(int DxfCode.ExtendedDataAsciiString, s) )
    let rb = new ResultBuffer(tvs)
    let xr = new Xrecord(Data = rb)
    ext.SetAt(key, xr)|> ignore
    tr.AddNewlyCreatedDBObject(xr, true)

    tr.Commit()

Makes a Xrecord from a ResultBuffer created from an array of TypedValue pairs corresponding to a string array and adds it with the key "xyz" to the ExtensionDictionary of LayerTable.  You didn't specify the language...

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Generic Dictionary
« Reply #6 on: July 21, 2011, 01:12:14 PM »
Do you guys think it would be too much of a performance hit to pass a object type to a method's parameter and use Reflection to take care of the adding the codetype?

Nice kaefer and dgorsman

cadpro

  • Guest
Re: Generic Dictionary
« Reply #7 on: July 21, 2011, 01:32:32 PM »

 You didn't specify the language...

Sorry, I'm working on VB.NET. Also, I wish to link the Dictionary to the whole drawing, rather than any Table in the drawing, so that this dictionary can be read from the drawing.

BTW, the dictionary contains Key as String and Value as List of String Array, that is, List(Of String()). So would it be possible to add to the DBDictionary?

Thanks
« Last Edit: July 21, 2011, 01:43:47 PM by cadpro »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Generic Dictionary
« Reply #8 on: July 21, 2011, 02:26:44 PM »

 You didn't specify the language...

Sorry, I'm working on VB.NET. Also, I wish to link the Dictionary to the whole drawing, rather than any Table in the drawing, so that this dictionary can be read from the drawing.

BTW, the dictionary contains Key as String and Value as List of String Array, that is, List(Of String()). So would it be possible to add to the DBDictionary?

Thanks

Is the key for searching,
and List(of String()) is different than a array-------For you C# List(of String()) == List<string>   Generic list 

cadpro

  • Guest
Re: Generic Dictionary
« Reply #9 on: July 21, 2011, 03:16:19 PM »
Sorry, I did not understand your question. Well, I have an already populated Dictionary. I can loop through the Dictionary's KeyValuePair to get the data in it. But don't know how to add it to a DBDictionary.

Thanks

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Generic Dictionary
« Reply #10 on: July 21, 2011, 04:47:25 PM »
Hi

Here's a C# snippet (maybe easier to translate to VB).

A DBDictionary named "StringArraysDictionary" is added (or overwriten) to the named object dictionary and filled with the entries of the Dictionary<string, List<string>> where each entry is considered as a Xrecord.

Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace DctionayDBDictionary
{
    public class Commands
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
            dict.Add("foo", new List<string> { "a", "b", "c" });
            dict.Add("bar", new List<string> { "x", "y", "z" });
            dict.Add("baz", new List<string> { "this", "is", "a", "test" });

            DictionaryToDBDictionary(dict, "StringArraysDictionary");
        }

        private void DictionaryToDBDictionary(Dictionary<string, List<string>> dict, string dictName)
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                DBDictionary dbDict;
                try
                {
                    dbDict = tr.GetObject(nod.GetAt(dictName), OpenMode.ForWrite) as DBDictionary;
                    foreach (DBDictionaryEntry entry in dbDict)
                    {
                        dbDict.Remove(entry.Key);
                    }
                }
                catch
                {
                    nod.UpgradeOpen();
                    dbDict = new DBDictionary();
                    nod.SetAt(dictName, dbDict);
                    tr.AddNewlyCreatedDBObject(dbDict, true);
                }
                foreach (KeyValuePair<string, List<string>> entry in dict)
                {
                    Xrecord xrec = new Xrecord();
                    ResultBuffer datas = new ResultBuffer();
                    foreach (string s in entry.Value)
                    {
                        datas.Add(new TypedValue(1, s));
                    }
                    xrec.Data = datas;
                    dbDict.SetAt(entry.Key, xrec);
                    tr.AddNewlyCreatedDBObject(xrec, true);
                }
                tr.Commit();
            }
        }
    }
}
Speaking English as a French Frog

cadpro

  • Guest
Re: Generic Dictionary
« Reply #11 on: July 21, 2011, 08:00:57 PM »
Hi,

Thanks very much for the code. That was a startup!

I did write it in VB and it works like a charm. But I want to retrieve this dictionary back too. For that, I did some code but not working.

Code: [Select]
Public Sub Test()
Dim dict as New Dictionary(of String, List(Of String()))
Dim a As String() = New String() {"a", "b"}
Dim b As String() = New String() {"c", "d"}
Dim c As String() = New String() {"e", "f"}
Dim d As String() = New String() {"g", "h"}
Dim e As String() = New String() {"i", "j"}
Dim f As String() = New String() {"k", "l"}

Dim r1 As New List(Of String())
Dim r2 As New List(Of String())
Dim r3 As New List(Of String())

r1.Add(a)
r1.Add(b)
r2.Add(c)
r2.Add(d)
r3.Add(e)
r3.Add(f)

dict.Add("xxx", r1)
dict.Add("yyy", r2)
dict.Add("zzz", r3)

End Sub

Public Sub GetXrecord()
        Dim doc As Document = acadApp.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim tr As Transaction = db.TransactionManager.StartTransaction

Dim nod as DBDictionary =Nothing
dim nodid as ObjectId =db.NamedObjectsDictionaryId

Using tr as Transaction = db.TransactionManager.StartTransaction
nod = CType(tr.GetObject(nodid, OpenMode.ForRead), DBDictionary)
If Not nod Is Nothing Then
If nod.Contains("StringArraysDictionary") Then
Dim dbDict as DBDictionary = Nothing
Dim idDict as ObjectId = nod.GetAt("StringArraysDictionary")
For Each e in dbDict
Dim xrec as XRecord = CType(tr.GetObject(dbDict.GetAt(e.Key), OpenMode.ForRead), Xrecord)
For Each x In xrec.Data
Dim s as String() = x.Value
Next
Next
End If
End If
End Using
End Sub 

Thanks

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Generic Dictionary
« Reply #12 on: July 22, 2011, 02:28:38 AM »
Code: [Select]
        [CommandMethod("testback")]
        public void TestBack()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Dictionary<string, List<string>> dict = DBDictionaryToDictionary("StringArraysDictionary");
            if (dict == null)
            {
                ed.WriteMessage("\nThe 'StringArraysDictionary' dictionary can'tbe found.");
                return;
            }
            foreach (KeyValuePair<string, List<string>> pair in dict)
            {
                string datas = string.Empty;
                foreach (string s in pair.Value)
                {
                    datas += " " + s;
                }
                ed.WriteMessage("\n{0} ={1}", pair.Key, datas);
            }
        }

        private Dictionary<string, List<string>> DBDictionaryToDictionary(string dictName)
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                try
                {
                    DBDictionary dbDict =
                        (DBDictionary)tr.GetObject(nod.GetAt(dictName), OpenMode.ForRead);
                    Dictionary<string, List<string>> result = new Dictionary<string,List<string>>();
                    foreach (DBDictionaryEntry entry in dbDict)
                    {
                        Xrecord xrec = tr.GetObject(entry.Value, OpenMode.ForRead) as Xrecord;
                        if (xrec == null)  continue;
                        List<string> strs = new List<string>();
                        ResultBuffer datas = xrec.Data;
                        if (datas == null) continue;
                        foreach (TypedValue tv in datas)
                        {
                            if (tv.TypeCode == 1)
                            {
                                strs.Add((string)tv.Value);
                            }
                        }
                        result.Add(entry.Key, strs);
                    }
                    return result;
                }
                catch
                {
                    return null;
                }
            }
        }
Speaking English as a French Frog

cadpro

  • Guest
Re: Generic Dictionary
« Reply #13 on: July 22, 2011, 04:02:01 AM »
Hi gile,

Thanks very much for the code.

My problem lies in adding and retrieving the String Array. My Dictionary contains String as Key and List of String Array as Value. That is

MyDict(Of String, List(Of String())

Hence even though adding the value does not give any error, I could step through to see that the value it takes is System.String[]
Same with retrieving also.

Thanks

cadpro

  • Guest
Re: Generic Dictionary
« Reply #14 on: July 22, 2011, 06:54:57 AM »
Hi,

The sample code posted is for List of String. But I'm looking for some code with List of String Array. I cannot get it to work. Any help please!!

Thanks