I created a class with about 40 properties in it
In another class I have created of generic list of the above class (lets just call it "A" here, & the list "Alist")
It seemed to me that the best way of populating my list would be to create a temporary variable of type "A" (let's call it "tempA"), do a wide variety of things to set the various properties of tempA, which involves creating a bunch of different objects (layer table records for example), and then adding tempA to Alist as follows:
Alist.add(tempA)
the problem with this is that every item in my list ends up being a reference to tempA,
so Instead of using tempA, I just directly set the current list member by keeping track of my count (which now starts getting into the extra code required that I'm trying to avoid by using lists in the first place). But this only "works" if I set the property to an actual value such as TRUE, or 15, etc, otherwise all list memebers still reference the same object such as a layertablerecord. So in a list of layernames that should be "a", "b",..."z", I end up with "z","z",..."z".
I do not want to create constructors for my class, & end up with :
Alist.add(layouttype, layoutname,layername,ison,isfrozen, etc, etc & 35 more items would go in this series)
is there a way to force or convert the referenced data to be byval?
should I just use an array instead?
why are lists byref to begin with? what good does that do?
I'm only learning myself but I was having the same problem adding many objects to a list and ended up using the following -
In a seperate sub/function I had
Sub AddAtoList()
tempA = New A
<code to populate tempA properties>
Alist.Add(tempA)
tempA = Nothing
End Sub
I'm sure one of the more experienced people can explain far better than me.
Hi,
It seems that you are missing some .NET/OOP basics.
All classes (except string) are reference type, on the other hand, structures are value type.
Both List and Array are reference type so using an array instead of a list won't solve your problem.
If I understand what you're tying to do: populate a list of a 'A' type using the default (without arguments) 'A' constructor to create instances of 'A' (I suppose you set each 'A' instance properties from the class where the list is build).
so, IMO your problem is due to the way you create each 'A' instance. In the class where you populate the list, you need to explicitly create a New instance of 'A' for each object
Here's a little sample (not related to AutoCAD):
C#
using System; using System.Collections.Generic; namespace GenericListSample { class Program { static void Main() { List<A> Alist = new List<A>(); A tempA = new A(); tempA.Name = "foo"; tempA.Index = 1; tempA.Date = new DateTime(2012, 11, 10); tempA.Position = new double[2] { 0.0, 0.0 }; Alist.Add(tempA); tempA = new A(); tempA.Name = "bar"; tempA.Index = 2; tempA.Date = new DateTime(2012, 11, 12); tempA.Position = new double[2] { 10.0, 20.0 }; Alist.Add(tempA); tempA = new A(); tempA.Name = "baz"; tempA.Index = 3; tempA.Date = new DateTime(2012, 11, 18); tempA.Position = new double[2] { 50.0, 30.0 }; Alist.Add(tempA); foreach (A a in Alist) { Console.WriteLine("Name: {0}, Index: {1}, Date: {2}, Position: {3}, {4}", a.Name, a.Index, a.Date, a.Position[0], a.Position[1]); } } } class A { public string Name { get; set; } // value type public int Index { get; set; } // value type public DateTime Date { get; set; } // reference type public double[] Position { get; set; } // reference type } }
VB
Imports System Imports System.Collections.Generic Namespace GenericListSample Class Program Public Shared Sub Main() Dim Alist As New List(Of A)() Dim tempA As New A() tempA.Name = "foo" tempA.Index = 1 tempA.TheDate = New DateTime(2012, 11, 10) tempA.Position = New Double(1) {0.0, 0.0} Alist.Add(tempA) tempA = New A() tempA.Name = "bar" tempA.Index = 2 tempA.TheDate = New DateTime(2012, 11, 12) tempA.Position = New Double(1) {10.0, 20.0} Alist.Add(tempA) tempA = New A() tempA.Name = "baz" tempA.Index = 3 tempA.TheDate = New DateTime(2012, 11, 18) tempA.Position = New Double(1) {50.0, 30.0} Alist.Add(tempA) For Each a As A In Alist Console.WriteLine("Name: {0}, Index: {1}, Date: {2}, Position: {3}, {4}", _ a.Name, a.Index, a.TheDate, a.Position(0), a.Position(1)) Next End Sub End Class Class A Private m_Name As String ' value type Private m_Index As Integer ' value type Private m_Date As DateTime ' reference type Private m_Position As Double() ' reference type Public Property Name() As String Get Return m_Name End Get Set(value As String) m_Name = value End Set End Property Public Property Index() As Integer Get Return m_Index End Get Set(value As Integer) m_Index = value End Set End Property Public Property TheDate() As DateTime Get Return m_Date End Get Set(value As DateTime) m_Date = Value End Set End Property Public Property Position() As Double() Get Return m_Position End Get Set(value As Double()) m_Position = value End Set End Property End Class End Namespace
Another way is to make 'A' type a structure rather than a class. As a structure is a value type, a new instance will be implictly created.
Here's the same sample as upper using a structure:
C#
using System; using System.Collections.Generic; namespace GenericListSample { class Program { static void Main() { List<B> Blist = new List<B>(); B tempB = new B(); tempB.Name = "foo"; tempB.Index = 1; tempB.Date = new DateTime(2012, 11, 10); tempB.Position = new double[2] { 0.0, 0.0 }; Blist.Add(tempB); tempB.Name = "bar"; tempB.Index = 2; tempB.Date = new DateTime(2012, 11, 12); tempB.Position = new double[2] { 10.0, 20.0 }; Blist.Add(tempB); tempB.Name = "baz"; tempB.Index = 3; tempB.Date = new DateTime(2012, 11, 18); tempB.Position = new double[2] { 50.0, 30.0 }; Blist.Add(tempB); foreach (B a in Blist) { Console.WriteLine("Name: {0}, Index: {1}, Date: {2}, Position: {3}, {4}", a.Name, a.Index, a.Date, a.Position[0], a.Position[1]); } } } struct B { public string Name { get; set; } // value type public int Index { get; set; } // value type public DateTime Date { get; set; } // reference type public double[] Position { get; set; } // reference type } }
VB
Imports System Imports System.Collections.Generic Namespace GenericListSample Class Program Public Shared Sub Main() Dim Blist As New List(Of B)() Dim tempB As New B() tempB.Name = "foo" tempB.Index = 1 tempB.TheDate = New DateTime(2012, 11, 10) tempB.Position = New Double(1) {0.0, 0.0} Blist.Add(tempB) tempB.Name = "bar" tempB.Index = 2 tempB.TheDate = New DateTime(2012, 11, 12) tempB.Position = New Double(1) {10.0, 20.0} Blist.Add(tempB) tempB.Name = "baz" tempB.Index = 3 tempB.TheDate = New DateTime(2012, 11, 18) tempB.Position = New Double(1) {50.0, 30.0} Blist.Add(tempB) For Each a As B In Blist Console.WriteLine("Name: {0}, Index: {1}, Date: {2}, Position: {3}, {4}", a.Name, a.Index, a.TheDate, a.Position(0), a.Position(1)) Next End Sub End Class Structure B Private m_Name As String ' value type Private m_Index As Integer ' value type Private m_Date As DateTime ' reference type Private m_Position As Double() ' reference type Public Property Name() As String Get Return m_Name End Get Set(value As String) m_Name = value End Set End Property Public Property Index() As Integer Get Return m_Index End Get Set(value As Integer) m_Index = value End Set End Property Public Property TheDate() As DateTime Get Return m_Date End Get Set(value As DateTime) m_Date = value End Set End Property Public Property Position() As Double() Get Return m_Position End Get Set(value As Double()) m_Position = value End Set End Property End Structure End Namespace
See here for more http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.90).aspx
Generic classes encapsulate operations that are not specific to a particular data type.
The most common use for generic classes is with collections like linked lists, hash tables,
stacks, queues, trees and so on where operations such as adding and removing items
from the collection are performed in much the same way regardless of the type of data
being stored. See here for more
http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.90).aspx
You can also to create a list of your classes like this
: List<List<MyClass>> master= new List<List<MyClass>>();
to add members to list see methods Add, AddRange,CopyTo etc:
http://msdn.microsoft.com/en-us/library/d9hw1as6(v=vs.90).aspx
_gile,
let me see if I got this striaght:
in your example a new instance of the class is created (3 times) with
Dim tempA = New A()
&
tempA = New A()
& the properties are filled in after each is created.
& then it it is added to the list via
Alist.Add(tempA)
wait a minute, I swear I tried something like that already, except I was using a loop to iterate through all the layers in a drawing. I had something like this
for each thingThing as thing in aThingFullOfThings tempA = New A tempA.Name = "foo" tempA.Index = 1 tempA.TheDate = New DateTime(2012, 11, 10) tempA.Position = New Double(1) {0.0, 0.0} Alist.Add(tempA) next
but I had A & Alist declared as class properties, with shared variables tied to the properties, one of which was a new list (of A).
could that be causing my problem?
I'm going to experiment a bit more. I don't need A & AList to be properties actually. I had copied what I did for another project which was my first atttempt using lists & it is unfinished so I never ran into my current problems
actually, I want to keep my properties in my main procedure class, because they would still be useful here, but manditory in another project, so I really need to figure this out.
I really don't see any difference between what I'm doing & your example, except for the fact that I'm trying to assign properties of other objects to my list member's properties. If I assign a particular string or an integer or whatever everything works as I expected it too.
To me it just seems like I need to somehow break the link between the list members' properties & the object's property that I'm extracting the information from such as LayerTableRecord.Name.
so to try to do this I created a temp variable of class A, & assigned values to its properties such as
tempA.Layername =LayerTableRecord.Name
then added tempA to Alist, then set tempA to nothing. Then in the next iteration of reading the layers created a new variable called tempA, (tempA = New A) which to me seems like it should be a new variable called tempA that has nothing to do with the first or 200th variable that was also called TempA. The results of my list is that all memeber's properties reflect the last TempA that was created instead of being unique.
here is my actual code:
Public Class FullLayerData Private strLayoutName As String Private strSpaceName As String Private strLayerName As String Private strColorName As String Private strLinetypeName As String Private strLineweightName As String Private strPlotStyleName As String Private strVpLayerColorName As String Private strVpLinetypeName As String Private strVpLineweightName As String Private strVpPlotStyleName As String Private booIsLayout As Boolean Private booIsModelSpace As Boolean Private booLayerON As Boolean Private booLayerFrozen As Boolean Private booLayerVpFrozen As Boolean Private booLayerNoPlot As Boolean Private booLayerNewFrozen As Boolean Private booIsColorVpOverridden As Boolean Private booIsLinetypVpOverridden As Boolean Private booIsLineweightVpOverridden As Boolean Private booIsPlotStyleVpOverridden As Boolean Private iVpNumber As Integer Private colLayerColor As Autodesk.AutoCAD.Colors.Color Private colVpLayerColor As Autodesk.AutoCAD.Colors.Color Public Property LayoutName() As String Get Return strLayoutName End Get Set(ByVal value As String) strLayoutName = value End Set End Property Public Property SpaceName() As String Get Return strSpaceName End Get Set(ByVal value As String) strSpaceName = value End Set End Property Public Property LayerName() As String Get Return strLayerName End Get Set(ByVal value As String) strLayerName = value End Set End Property Public Property ColorName() As String Get Return strColorName End Get Set(ByVal value As String) strColorName = value End Set End Property Public Property LinetypeName() As String Get Return strLinetypeName End Get Set(ByVal value As String) strLinetypeName = value End Set End Property Public Property LineweightName() As String Get Return strLineweightName End Get Set(ByVal value As String) strLineweightName = value End Set End Property Public Property PlotStyleName() As String Get Return strPlotStyleName End Get Set(ByVal value As String) strPlotStyleName = value End Set End Property Public Property VpLayerColorName() As String Get Return strVpLayerColorName End Get Set(ByVal value As String) strVpLayerColorName = value End Set End Property Public Property VpLinetypeName() As String Get Return strVpLinetypeName End Get Set(ByVal value As String) strVpLinetypeName = value End Set End Property Public Property VpLineweightName() As String Get Return strVpLineweightName End Get Set(ByVal value As String) strVpLineweightName = value End Set End Property Public Property VpPlotStyleName() As String Get Return strVpPlotStyleName End Get Set(ByVal value As String) strVpPlotStyleName = value End Set End Property Public Property IsLayout() As Boolean Get Return booIsLayout End Get Set(ByVal value As Boolean) booIsLayout = value End Set End Property Public Property IsModelSpace() As Boolean Get Return booIsModelSpace End Get Set(ByVal value As Boolean) booIsModelSpace = value End Set End Property Public Property LayerON() As Boolean Get Return booLayerON End Get Set(ByVal value As Boolean) booLayerON = value End Set End Property Public Property LayerFrozen() As Boolean Get Return booLayerFrozen End Get Set(ByVal value As Boolean) booLayerFrozen = value End Set End Property Public Property LayerVpFrozen() As Boolean Get Return booLayerVpFrozen End Get Set(ByVal value As Boolean) booLayerVpFrozen = value End Set End Property Public Property LayerNoPlot() As Boolean Get Return booLayerNoPlot End Get Set(ByVal value As Boolean) booLayerNoPlot = value End Set End Property Public Property LayerNewFrozen() As Boolean Get Return booLayerNewFrozen End Get Set(ByVal value As Boolean) booLayerNewFrozen = value End Set End Property Public Property IsColorVpOverridden() As Boolean Get Return booIsColorVpOverridden End Get Set(ByVal value As Boolean) booIsColorVpOverridden = value End Set End Property Public Property IsLinetypVpOverridden() As Boolean Get Return booIsLinetypVpOverridden End Get Set(ByVal value As Boolean) booIsLinetypVpOverridden = value End Set End Property Public Property IsLineweightVpOverridden() As Boolean Get Return booIsLineweightVpOverridden End Get Set(ByVal value As Boolean) booIsLineweightVpOverridden = value End Set End Property Public Property IsPlotStyleVpOverridden() As Boolean Get Return booIsPlotStyleVpOverridden End Get Set(ByVal value As Boolean) booIsPlotStyleVpOverridden = value End Set End Property Public Property VpNumber() As Integer Get Return iVpNumber End Get Set(ByVal value As Integer) iVpNumber = value End Set End Property Public Property LayerColor() As Autodesk.AutoCAD.Colors.Color Get Return colLayerColor End Get Set(ByVal value As Autodesk.AutoCAD.Colors.Color) colLayerColor = value End Set End Property Public Property VpLayerColor() As Autodesk.AutoCAD.Colors.Color Get Return colVpLayerColor End Get Set(ByVal value As Autodesk.AutoCAD.Colors.Color) colVpLayerColor = value End Set End Property End Class
Public Class ClassXLLayerMan 'a bunch of variable declarations go here, & then... Shared liFullLayerDataList As New List(Of FullLayerData) Shared fldNewFLD As FullLayerData Public Property FullLayerDataList() As List(Of FullLayerData) Get Return liFullLayerDataList End Get Set(ByVal value As List(Of FullLayerData)) liFullLayerDataList = value End Set End Property Private Property NewFLD() As FullLayerData Get Return fldNewFLD End Get Set(ByVal value As FullLayerData) fldNewFLD = value End Set End Property
'...a bunch of subs not directly related to the problem go here, & then... Private Sub AddFullLayerDataForEachAutocadVP() Dim LayLayout As Layout Dim strLayoutName As String Dim dictLayouts As DBDictionary Dim vpVP As Viewport 'Dim iVpNum As Integer Dim iCurrentCvports As Integer = CInt(Application.GetSystemVariable("CVPORT")) Dim iCurrentTilemode As Integer = CInt(Application.GetSystemVariable("TILEMODE")) Dim MeaninglessId As ObjectId ' Dim FLDcount As Integer ' FLDcount = 0 FullLayerDataList.Clear() FullLayerDataList.TrimExcess() Using Tx As Transaction = ACF.Db.TransactionManager.StartTransaction LT = CType(Tx.GetObject(ACF.Db.LayerTableId, OpenMode.ForRead), LayerTable) dictLayouts = CType(Tx.GetObject(ACF.Db.LayoutDictionaryId, OpenMode.ForRead), DBDictionary) For Each DE1 As DBDictionaryEntry In dictLayouts If DE1.Key.ToString() = "Model" Then strLayoutName = "Model" LayoutManager.Current.CurrentLayout = strLayoutName Application.SetSystemVariable("TILEMODE", 1) NewFLD = New FullLayerData FullLayerDataList.Add(NewFLD) NewFLD.IsLayout = False NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = False NewFLD.SpaceName = "Model" MeaninglessId = DE1.Value 'ReadLayerDataFromAutocad(DE1, False, MeaninglessId, FLDcount) ReadLayerDataFromAutocad(DE1, False, MeaninglessId) NewFLD = Nothing 'FLDcount = FLDcount + 1 Else End If Next DE1 For Each DE As DBDictionaryEntry In dictLayouts If Not DE.Key.ToString() = "Model" Then LayLayout = CType(Tx.GetObject(CType(DE.Value, ObjectId), OpenMode.ForRead), Layout) strLayoutName = LayLayout.LayoutName LayoutManager.Current.CurrentLayout = strLayoutName For Each id As ObjectId In LayLayout.GetViewports NewFLD = New FullLayerData FullLayerDataList.Add(NewFLD) vpVP = CType(Tx.GetObject(id, OpenMode.ForRead), Viewport) NewFLD.VpNumber = vpVP.Number If NewFLD.VpNumber = 1 Then 'first VP should be PS, strVpNum is nothing until first VP is iterated ACF.Ed.SwitchToPaperSpace() Application.SetSystemVariable("cvport", NewFLD.VpNumber) NewFLD.IsLayout = True NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = False NewFLD.SpaceName = "PS" NewFLD.VpNumber = NewFLD.VpNumber 'ReadLayerDataFromAutocad(DE, True, id, FLDcount) ReadLayerDataFromAutocad(DE, True, id) NewFLD = Nothing ACF.Ed.SwitchToPaperSpace() Else ACF.Ed.SwitchToModelSpace() Application.SetSystemVariable("cvport", NewFLD.VpNumber) vpVP.UpdateDisplay() NewFLD.IsLayout = True NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = True NewFLD.SpaceName = "MS" NewFLD.VpNumber = NewFLD.VpNumber 'ReadLayerDataFromAutocad(DE, True, id, FLDcount) ReadLayerDataFromAutocad(DE, True, id) NewFLD = Nothing ACF.Ed.SwitchToPaperSpace() End If 'FLDcount = FLDcount + 1 Next id End If Next DE End Using End Sub ' Public Sub ReadLayerDataFromAutocad(ByVal subDE As DBDictionaryEntry, ByRef SubIsLayout As Boolean, ByVal subID As ObjectId, ByRef subFLDcount As Integer) 'SubIsLayout needs to set to false for the model tab, & true for all layout tabs Public Sub ReadLayerDataFromAutocad(ByVal subDE As DBDictionaryEntry, ByRef SubIsLayout As Boolean, ByVal subID As ObjectId) Dim LTR As LayerTableRecord Dim idLineType As ObjectId Dim LTTR As LinetypeTableRecord Dim LVP As LayerViewportProperties Dim vpVP1 As Viewport For Each LTRid As ObjectId In LT ' Dim supertempFLD = New FullLayerData Using Tx1 As Transaction = ACF.Db.TransactionManager.StartTransaction LTR = CType(Tx1.GetObject(LTRid, OpenMode.ForRead), LayerTableRecord) NewFLD.LayerName = LTR.Name NewFLD.ColorName = LTR.Color.ColorNameForDisplay NewFLD.LayerColor = LTR.Color If SubIsLayout = "true" Then LVP = LTR.GetViewportOverrides(subID) vpVP1 = CType(Tx1.GetObject(subID, OpenMode.ForRead), Viewport) If LVP.IsColorOverridden = True Then NewFLD.IsColorVpOverridden = True NewFLD.VpLayerColorName = LVP.Color.ColorNameForDisplay NewFLD.VpLayerColor = LVP.Color 'rRange.Font.Color = Col2Str(LVP.Color) '/<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Else End If If LVP.IsPlotStyleOverridden = True Then NewFLD.IsPlotStyleVpOverridden = True NewFLD.VpPlotStyleName = LVP.PlotStyleName Else End If If LVP.IsLinetypeOverridden = True Then idLineType = LVP.LinetypeObjectId LTTR = CType(Tx1.GetObject(idLineType, OpenMode.ForRead), LinetypeTableRecord) NewFLD.IsLinetypVpOverridden = True NewFLD.VpLinetypeName = LTTR.Name Else End If If vpVP1.IsLayerFrozenInViewport(LTRid) = True Then 'freeze = yes NewFLD.LayerVpFrozen = True Else End If End If NewFLD.PlotStyleName = LTR.PlotStyleName idLineType = LTR.LinetypeObjectId LTTR = CType(Tx1.GetObject(idLineType, OpenMode.ForRead), LinetypeTableRecord) NewFLD.LinetypeName = LTTR.Name If LTR.IsOff = True Then Else NewFLD.LayerON = True End If If LTR.IsFrozen = True Then 'freeze = yes NewFLD.LayerFrozen = True Else 'freeze = no End If If LTR.IsPlottable = True Then 'noplot = no Else NewFLD.LayerNoPlot = True End If End Using Next End Sub
sorry guys, I was trying to edit my code to revert it back to another state & I left a few thing out. Please IGNORE the last block of code in my previous post, which should be this:
Private Sub AddFullLayerDataForEachAutocadVP() Dim LayLayout As Layout Dim strLayoutName As String Dim dictLayouts As DBDictionary Dim vpVP As Viewport 'Dim iVpNum As Integer Dim iCurrentCvports As Integer = CInt(Application.GetSystemVariable("CVPORT")) Dim iCurrentTilemode As Integer = CInt(Application.GetSystemVariable("TILEMODE")) Dim MeaninglessId As ObjectId ' Dim FLDcount As Integer ' FLDcount = 0 FullLayerDataList.Clear() FullLayerDataList.TrimExcess() Using Tx As Transaction = ACF.Db.TransactionManager.StartTransaction LT = CType(Tx.GetObject(ACF.Db.LayerTableId, OpenMode.ForRead), LayerTable) dictLayouts = CType(Tx.GetObject(ACF.Db.LayoutDictionaryId, OpenMode.ForRead), DBDictionary) For Each DE1 As DBDictionaryEntry In dictLayouts If DE1.Key.ToString() = "Model" Then strLayoutName = "Model" LayoutManager.Current.CurrentLayout = strLayoutName Application.SetSystemVariable("TILEMODE", 1) NewFLD = New FullLayerData NewFLD.IsLayout = False NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = False NewFLD.SpaceName = "Model" MeaninglessId = DE1.Value 'ReadLayerDataFromAutocad(DE1, False, MeaninglessId, FLDcount) ReadLayerDataFromAutocad(DE1, False, MeaninglessId) NewFLD = Nothing FullLayerDataList.Add(NewFLD) 'FLDcount = FLDcount + 1 Else End If Next DE1 For Each DE As DBDictionaryEntry In dictLayouts If Not DE.Key.ToString() = "Model" Then LayLayout = CType(Tx.GetObject(CType(DE.Value, ObjectId), OpenMode.ForRead), Layout) strLayoutName = LayLayout.LayoutName LayoutManager.Current.CurrentLayout = strLayoutName For Each id As ObjectId In LayLayout.GetViewports NewFLD = New FullLayerData vpVP = CType(Tx.GetObject(id, OpenMode.ForRead), Viewport) NewFLD.VpNumber = vpVP.Number If NewFLD.VpNumber = 1 Then 'first VP should be PS, strVpNum is nothing until first VP is iterated ACF.Ed.SwitchToPaperSpace() Application.SetSystemVariable("cvport", NewFLD.VpNumber) NewFLD.IsLayout = True NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = False NewFLD.SpaceName = "PS" NewFLD.VpNumber = NewFLD.VpNumber 'ReadLayerDataFromAutocad(DE, True, id, FLDcount) ReadLayerDataFromAutocad(DE, True, id) FullLayerDataList.Add(NewFLD) NewFLD = Nothing ACF.Ed.SwitchToPaperSpace() Else ACF.Ed.SwitchToModelSpace() Application.SetSystemVariable("cvport", NewFLD.VpNumber) vpVP.UpdateDisplay() NewFLD.IsLayout = True NewFLD.LayoutName = strLayoutName NewFLD.IsModelSpace = True NewFLD.SpaceName = "MS" NewFLD.VpNumber = NewFLD.VpNumber 'ReadLayerDataFromAutocad(DE, True, id, FLDcount) ReadLayerDataFromAutocad(DE, True, id) FullLayerDataList.Add(NewFLD) NewFLD = Nothing ACF.Ed.SwitchToPaperSpace() End If 'FLDcount = FLDcount + 1 Next id End If Next DE End Using End Sub ' Public Sub ReadLayerDataFromAutocad(ByVal subDE As DBDictionaryEntry, ByRef SubIsLayout As Boolean, ByVal subID As ObjectId, ByRef subFLDcount As Integer) 'SubIsLayout needs to set to false for the model tab, & true for all layout tabs Public Sub ReadLayerDataFromAutocad(ByVal subDE As DBDictionaryEntry, ByRef SubIsLayout As Boolean, ByVal subID As ObjectId) Dim LTR As LayerTableRecord Dim idLineType As ObjectId Dim LTTR As LinetypeTableRecord Dim LVP As LayerViewportProperties Dim vpVP1 As Viewport For Each LTRid As ObjectId In LT ' Dim supertempFLD = New FullLayerData Using Tx1 As Transaction = ACF.Db.TransactionManager.StartTransaction LTR = CType(Tx1.GetObject(LTRid, OpenMode.ForRead), LayerTableRecord) NewFLD.LayerName = LTR.Name NewFLD.ColorName = LTR.Color.ColorNameForDisplay NewFLD.LayerColor = LTR.Color If SubIsLayout = "true" Then LVP = LTR.GetViewportOverrides(subID) vpVP1 = CType(Tx1.GetObject(subID, OpenMode.ForRead), Viewport) If LVP.IsColorOverridden = True Then NewFLD.IsColorVpOverridden = True NewFLD.VpLayerColorName = LVP.Color.ColorNameForDisplay NewFLD.VpLayerColor = LVP.Color 'rRange.Font.Color = Col2Str(LVP.Color) '/<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Else End If If LVP.IsPlotStyleOverridden = True Then NewFLD.IsPlotStyleVpOverridden = True NewFLD.VpPlotStyleName = LVP.PlotStyleName Else End If If LVP.IsLinetypeOverridden = True Then idLineType = LVP.LinetypeObjectId LTTR = CType(Tx1.GetObject(idLineType, OpenMode.ForRead), LinetypeTableRecord) NewFLD.IsLinetypVpOverridden = True NewFLD.VpLinetypeName = LTTR.Name Else End If If vpVP1.IsLayerFrozenInViewport(LTRid) = True Then 'freeze = yes NewFLD.LayerVpFrozen = True Else End If End If NewFLD.PlotStyleName = LTR.PlotStyleName idLineType = LTR.LinetypeObjectId LTTR = CType(Tx1.GetObject(idLineType, OpenMode.ForRead), LinetypeTableRecord) NewFLD.LinetypeName = LTTR.Name If LTR.IsOff = True Then Else NewFLD.LayerON = True End If If LTR.IsFrozen = True Then 'freeze = yes NewFLD.LayerFrozen = True Else 'freeze = no End If If LTR.IsPlottable = True Then 'noplot = no Else NewFLD.LayerNoPlot = True End If End Using Next End Sub
Hi,
Sorry it's quite difficult for me to read VB, and the code you posted does not show all the project structure (Namespaces (?), Modules (?) Imports, ...).
But, from what I can read, the ClassXLLayerMan is absolutely unusefull and does not make the code easily readable.
I'd use local variables in the AddFullLayerDataForEachAutocadVP() method, for the FullDataLayer and List<fullDataLayer> instances and pass each FullDataLayer instance ByRef to the ReadLayerDataFromAutocad() method.
Private Sub AddFullLayerDataForEachAutocadVP() '... Dim layerDataList As List(Of FullLayerData) = New List(Of FullLayerData) '... For Each DE1 As DBDictionaryEntry In dictLayouts '... newFLD = New FullLayerData '... ReadLayerDataFromAutocad(DE1, newFLD, False, MeaninglessId) FullLayerDataList.Add(NewFLD) '... Next DE1 '... End Sub Public Sub ReadLayerDataFromAutocad(ByVal subDE As DBDictionaryEntry, ByRef fld As FullLayerData, _ ByRef SubIsLayout As Boolean, ByVal subID As ObjectId) '... End Sub
In the ReadLayerDataFromAutocad(), you change the properties of NewFLD for each LayerTableRecord in the LayerTable (and start a new Transaction which is unusefull as this method from within the transaction opened in the calling method).
using a STRUCTURE did the trick. I really don't understand why, but I will hopefully someday ( I am a newbie after all).
thanks for the helps.
Hi,
Have a look here and/or google for "Value type vs Reference type".
You can also run this little console application which is quite self explanatory:
class RefType { public string Name; public RefType(string name) { Name = name; } } struct ValType { public string Name; public ValType(string name) { Name = name; } } class Program { static void Main() { ValType val1 = new ValType("val1"); ValType val2 = val1; RefType ref1 = new RefType("ref1"); RefType ref2 = ref1; val2.Name = "val2"; ref2.Name = "ref2"; Console.WriteLine(val1.Name); // prints: "val1" Console.WriteLine(val2.Name); // prints: "val2" Console.WriteLine(ref1.Name); // prints: "ref2" Console.WriteLine(ref2.Name); // prints: "ref2" } }
Your problem is your adding a shared (static) field of a class however many times.
So a shared or static variable for a reference type like in your code points to the same memory location(it actually might get moved around some for optimization), but that variable will always point to same object., and you are just changing the properties of the same object.
A variable is just a way in your source code for a name to point to a memory slot.
A couple of points
Reference types by default are passed by value contrary to what you read in books, etc...
A value type point to the memory slots that actually that contain the data..
A variable for a reference type points to a memory slot that holds only 2 things.
1. Null
2. The address in memory where the object data is stored.
Dim a as New Class
That just creates a Class object then the varaible 'a' points to a memory slot which contains the address to the object.
Dim b as Class = a
Now b is a different memory slot but is assigned the value of 'a' which is the address of same object.
a.Property = 3
b.Property = 4
All that is happening is when you assign the property using a or b is they are told to modify the property of the object located at the same address.
Anything you change with a or b they are going to the same place to update the data.
That is one reason people say reference types are passed by ref.
You can assign a = null but b still holds the address to the object.
or
Dim c as new Class
b = c
now b and c hold the address that points to the same object and 'a' value is the address of first object created
Now if you pass a reference type by byref you are associating the argument with the same memory slot.
So they both will modify the same object but they both go to the smae memory slot to get that address.
So setting one to null then both will be null
Strings are just a an array of chars and are actully a reference type but are imuttable so they act like a value type.
I got a boss on top of me wanting to get a project out and typed this very quickly so probaly not very clear but I was actully planning on doing a post about this topic that will explain it much better with code and pics and go over so other fundamentals that would help expalin it, but boss man is about to come back in check on progress so will give a much better explanation in the next couple of days
The first part was incorrect your not changing the object your changing address it holds which points to a different object.
So a shared or static variable for a reference type like in your code points to the same memory location(it actually might get moved around some for optimization), but that variable will always points to the same memory location., and you are just changing the addresss it points to.
>>I got a boss on top of me wanting to get a project out and typed this very quickly so probaly not very clear but I was actully planning on doing a post about this topic that will explain it much better with code and pics and go over so other fundamentals that would help expalin it, but boss man is about to come back in check on progress so will give a much better explanation in the next couple of days<<
Probably we would NOT let the boss man and colleagues to know that we are playing around with this forum during working hours. 🙂