Author Topic: Generic Dictionary  (Read 14708 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

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Generic Dictionary
« Reply #15 on: July 22, 2011, 08:28:53 AM »
If your Dictionary entries values are list of string arrays, you have to go on level deeper in the DBDictionary because, as you ca see in the samples, the Xrecord.Value is a ResulBuffer and a TypedValue cannot contain a string array.

So, you have to add first DBDictionary (as NOD child or extension dictionary of a DBObject).
In this first dictionary, add one DBDictionary per List (entry of the source Dictionary).
In each of these DBDictionaries an Xrecord for each string array in the List (with incremented names for example).
And fill the Xrecord.Value with the string contained in the array.
Speaking English as a French Frog

kaefer

  • Guest
Re: Generic Dictionary
« Reply #16 on: July 22, 2011, 09:52:51 AM »
If your Dictionary entries values are list of string arrays, you have to go on level deeper in the DBDictionary because, as you ca see in the samples, the Xrecord.Value is a ResulBuffer and a TypedValue cannot contain a string array.

Now, that's much too complicated for me. And besides, if the 'customer' doesn't have their specifications nailed down and their goalposts are in danger of shifting, there's always another joker up our sleeves: serialization. Too bad this won't work with Xml; but the BinaryFormatter is still good enough:

Code: [Select]
let out (x : 'a) =
    let formatter = new Formatters.Binary.BinaryFormatter()
    use ms = new System.IO.MemoryStream()
    formatter.Serialize(ms, x)
    System.Convert.ToBase64String(
        ms.GetBuffer(),
        System.Base64FormattingOptions.InsertLineBreaks )
   
let in' txt =
    let ms = new System.IO.MemoryStream(System.Convert.FromBase64String txt)
    let formatter = new Formatters.Binary.BinaryFormatter()
    try
        formatter.Deserialize ms :?> _
    finally
        ms.Dispose()
   
let xToXrecord x xrName =
    let db = HostApplicationServices.WorkingDatabase
    use tr = db.TransactionManager.StartTransaction()
   
    let nod = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite) :?> DBDictionary
    let tvs =
        x |> out |> fun s ->
            s.Split([|'\r'; '\n'|], System.StringSplitOptions.RemoveEmptyEntries)
        |> Array.map (fun s ->
            new TypedValue(int DxfCode.Text, s) )
    let rb = new ResultBuffer(tvs)
    let xr = new Xrecord(Data = rb)
    nod.SetAt(xrName, xr) |> ignore
    tr.AddNewlyCreatedDBObject(xr, true)

    tr.Commit()

let xrecordToX xrName =
    let db = HostApplicationServices.WorkingDatabase
    use tr = db.TransactionManager.StartTransaction()

    let nod = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead) :?> DBDictionary
    let xr = tr.GetObject(nod.GetAt xrName, OpenMode.ForRead) :?> Xrecord
    let sb = new System.Text.StringBuilder()
    for tv in xr.Data do
        if tv.TypeCode = int16 DxfCode.Text then
            sb.Append tv.Value |> ignore
    sb.ToString() |> in'

[<CommandMethod "TEST">]
let test() =
    let 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" |])
    xToXrecord dict "StringArraysDictionary"

[<CommandMethod "TESTBACK">]
let testBack() =
    let ed = acadApp.DocumentManager.MdiActiveDocument.Editor
    try
        let dict : Dictionary<string, List<string>> =
            xrecordToX "StringArraysDictionary"
        for KeyValue(k, v) in dict do
            ed.WriteMessage("\n{0} = ", k)
            for s in v do
                ed.WriteMessage("{0} ", s)
    with _ ->
        ed.WriteMessage "\nThe 'StringArraysDictionary' dictionary can't be found. "


cadpro

  • Guest
Re: Generic Dictionary
« Reply #17 on: July 24, 2011, 09:27:26 PM »
Hi,

This code looks promising. Thanks kaefer. But could someone please convert this code for me to C# or VB.NET?

Thanks

kaefer

  • Guest
Re: Generic Dictionary
« Reply #18 on: July 25, 2011, 09:53:50 AM »
But could someone please convert this code for me to C# or VB.NET?

I'm sorry cadpro, I can't do that.

But you can have a look at my latest, new and improved version, all-singing, all-dancing; which uses DxfCode.BinaryChunk instead of text, and as icing on the top gzip compression too. That last feature is a bear, there's no seek and no direct buffer access on a compressed stream, so there are lots of MemoryStreams around and I'm still not sure if there's a better way to do it...

Code: [Select]
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SerializedObjectGZippedXrecord
{
    public class Commands
    {
        Database db;
        Editor ed;
        public Commands(){
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            db = doc.Database;
            ed = doc.Editor;
        }
           
        [CommandMethod("TestGz")]
        public void TestGz()
        {
            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" });

            XToXrecord(dict, "StringArraysDictionary");
        }

        private void XToXrecord(object o, string key)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (MemoryStream ins = new MemoryStream())
            using (MemoryStream outs = new MemoryStream())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(ins, o);
                byte[] ibuf = ins.ToArray();

                using (GZipStream gz = new GZipStream(outs, CompressionMode.Compress))
                    gz.Write(ibuf, 0, ibuf.Length);
                byte[] obuf = outs.ToArray();

                ResultBuffer rb = new ResultBuffer();
                const int chunkSize = 127;
                int bytesConsumed = 0;
                while (bytesConsumed < obuf.Length)
                {
                    int bytesToRead = obuf.Length - bytesConsumed;
                    int count = bytesToRead < chunkSize ? bytesToRead : chunkSize;
                    byte[] chunk = new byte[count];
                    Array.Copy(obuf, bytesConsumed, chunk, 0, count);
                    rb.Add(new TypedValue((int) DxfCode.BinaryChunk, chunk));
                    bytesConsumed += count;
                }
                Xrecord xrec = new Xrecord();
                xrec.Data = rb;
               
                nod.SetAt(key, xrec);
                tr.AddNewlyCreatedDBObject(xrec, true);

                tr.Commit();
            }
        }

        [CommandMethod("TestGzBack")]
        public void TestGzBack()
        {
            var dict = XrecordToX("StringArraysDictionary") as Dictionary<string, List<string>>;
            if (dict == null)
            {
                ed.WriteMessage("\nThe 'StringArraysDictionary' dictionary can't be 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 object XrecordToX(string key)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (MemoryStream ins = new MemoryStream())
            using (MemoryStream outs = new MemoryStream())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                try
                {
                    Xrecord xrec = (Xrecord)tr.GetObject(nod.GetAt(key), OpenMode.ForRead);
                    foreach(TypedValue tv in xrec.Data){
                        if (tv.TypeCode == (int)DxfCode.BinaryChunk)
                        {
                            byte[] buf = (byte[])tv.Value;
                            ins.Write(buf, 0, buf.Length);
                        }
                    }
                    ins.Position = 0;
                    using (GZipStream gz = new GZipStream(ins, CompressionMode.Decompress))
                        gz.CopyTo(outs);

                    outs.Position = 0;
                    BinaryFormatter formatter = new BinaryFormatter();
                    return (formatter.Deserialize(outs));
                }
                catch
                {
                    return null;
                }
            }
        }
    }
    public static class Extensions
    {
        public static void CopyTo(this Stream ins, Stream outs)
        {
            const int bufSize = 4096;
            byte[] buf = new byte[bufSize];
            int readBytes;
            do
            {
                readBytes = ins.Read(buf, 0, buf.Length);
                if (readBytes > 0)
                    outs.Write(buf, 0, readBytes);
            }
            while (readBytes == bufSize);
        }
    }
}

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Generic Dictionary
« Reply #19 on: July 25, 2011, 02:12:52 PM »
I see you trying to use a Dictionary<string, List<string[]>>-----I missed the extra parentheses

kaefer's solution is better but here is one hard-coded and doing what gile mentioned in previous post.

This is a example and has it pit falls but just for example to show you one way of nesting it.
So you need to modify it.

This made me go cross-eyed using Dictionary<string, List<string[]>>



Commands

Code: [Select]
  const string DIC_NAME = "HpadDictionary";       
        [CommandMethod("XrecordDictionaryAdd")]
        public void XrecordDictionaryAdd()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            using (Transaction trx = db.TransactionManager.StartTransaction())
            {

                Dictionary<string, List<string[]>> dictionary = new Dictionary<string, List<string[]>>();
                string[] valsA1 = { "A1-1", "A1-2" };
                string[] valsA2 = { "A2-1", "A2-2" };
                dictionary.Add("A", new List<string[]> {valsA1, valsA2});
                string[] valsB1 = { "B1-1", "B1-2" };
                string[] valsB2 = { "B2-1", "B2-2" };
                dictionary.Add("B", new List<string[]> { valsB1, valsB2 });

                XrecordInfo xi = new XrecordInfo(DIC_NAME);

                xi.AddDict(dictionary); 
                trx.Commit();
            }
        }

        [CommandMethod("XrecordDictionaryGet")]
        public void XrecordDictionaryGet()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
                XrecordInfo xi = new XrecordInfo(DIC_NAME);           
                Dictionary<string, List<string[]>> dictionary = xi.GetDict();

                foreach (KeyValuePair<string, List<string[]>> kvp in dictionary)
                {
                    ed.WriteMessage("\n{0}", kvp.Key);
                    int i = 1;
                    foreach (string[] strings in kvp.Value)
                    {

                        ed.WriteMessage("\n{0,15:D} {1}","Array", i);
                        foreach (string str in strings)
                        {
                            ed.WriteMessage("\n{0,15:D}", str);
                        }
                        i++;
                    }

                }

                trx.Commit();
            }
        }

Not very good but for example Helper Class
Code: [Select]

    public class XrecordInfo
     {
     
         private Database _db;
         private Transaction _trx;
         Database db { get { return _db; } }
         Transaction trx { get { return _trx; } }
         string DictionaryName { get; set; }


         public XrecordInfo()
         {
             _db = HostApplicationServices.WorkingDatabase;
             _trx = _db.TransactionManager.TopTransaction;
         
         }


         public XrecordInfo(string dictName)
             : this()
         {
             DictionaryName = dictName;
         }

 
         public void AddDict(Dictionary<string, List<string[]>> dict)
         {

             DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
             DBDictionary dic = new DBDictionary();
             nod.SetAt(DictionaryName, dic);
             trx.AddNewlyCreatedDBObject(dic, true);

             foreach(KeyValuePair<string, List<string[]>> kvp in dict)
             {                                                 
                 DBDictionary nestedDic = new DBDictionary();
                 dic.SetAt(kvp.Key, nestedDic);
                 trx.AddNewlyCreatedDBObject(nestedDic, true);
                 int i = 1;
                 foreach (string[] vals in kvp.Value)
                 {
                     Xrecord xr = new Xrecord();
                     TypedValueList tvl = new TypedValueList();
                     
                     foreach (string val in vals)
                     {
                         tvl.Add(1, val);
                     }
                     xr.Data = tvl;
                     nestedDic.SetAt(String.Format("array{0}", i), xr);
                     trx.AddNewlyCreatedDBObject(xr, true);
                     i++;
                 }
                 
             
             }


         }

         public Dictionary<string, List<string[]>> GetDict()
         {                                                                                             
             Dictionary<string, List<string[]>> dictionary = new Dictionary<string, List<string[]>>();

             DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
             DBDictionary dic = (DBDictionary)trx.GetObject(nod.GetAt(DictionaryName), OpenMode.ForRead);

             foreach (DBDictionaryEntry entry in dic)
             {
                 DBDictionary nestedDic = (DBDictionary)trx.GetObject(dic.GetAt(entry.Key), OpenMode.ForRead);
                 List<string[]> vals = new List<string[]>();
                 foreach (DBDictionaryEntry nestedEntry in nestedDic)
                 {

                     Xrecord xr = (Xrecord)trx.GetObject(nestedDic.GetAt(nestedEntry.Key), OpenMode.ForRead);

                     TypedValueList tvl = xr.Data;
                     string[] strings = new string[tvl.Count];
                     for (int i = 0; i < tvl.Count; i++)
                     {
                         strings[i] = tvl[i].Value.ToString();
                     }
                     vals.Add(strings);
                 }

                 dictionary.Add(entry.Key, vals); 
                                     
                                 
             }


             return dictionary;

         }

     }




Uses Tony T's TypedValueList
Code: [Select]
public class TypedValueList : List<TypedValue>
    {
        // With thanks to Tony Tanzillo
        // http://www.theswamp.org/index.php?topic=14495.msg186823#msg186823
        //
        public TypedValueList(params TypedValue[] args)
        {
            AddRange(args);
        }

        // Make it a bit easier to add items:

        public void Add(int typecode, object value)
        {
            base.Add(new TypedValue(typecode, value));
        }
        public void Add(LispDataType type, object value)
        {
            Add(new TypedValue((int)type, value));
        }
        public void Add(DxfCode code, object value)
        {
            Add(new TypedValue((int)code, value));
        }

        // Implicit conversion to SelectionFilter
        public static implicit operator SelectionFilter(TypedValueList src)
        {
            return src != null ? new SelectionFilter(src) : null;
        }

        // Implicit conversion to ResultBuffer
        public static implicit operator ResultBuffer(TypedValueList src)
        {
            return src != null ? new ResultBuffer(src) : null;
        }

        // Implicit conversion to TypedValue[]
        public static implicit operator TypedValue[](TypedValueList src)
        {
            return src != null ? src.ToArray() : null;
        }

        // Implicit conversion from TypedValue[]
        public static implicit operator TypedValueList(TypedValue[] src)
        {
            return src != null ? new TypedValueList(src) : null;
        }

        // Implicit conversion from SelectionFilter
        public static implicit operator TypedValueList(SelectionFilter src)
        {
            return src != null ? new TypedValueList(src.GetFilter()) : null;
        }

        // Implicit conversion from ResultBuffer
        public static implicit operator TypedValueList(ResultBuffer src)
        {
            return src != null ? new TypedValueList(src.AsArray()) : null;
        }
    }