Unable to compare 2 objects of same type - vb.net

Dim obj As New CMS_Page
Dim comparisonObj As New CMS_Page
The assignment
obj = db.CMS_Pages.First(Function(s) s.PageID = pageID)
comparisonObj = db.CMS_Pages.First(Function(s) s.PageID = pageID)
Somwhere in the middle of my code
obj.property = sometextfield.text 'Apparently this also changes the comparisonObj
Basically what I'm doing in the end would be
if (obj.property = comparisonObj.property) then
//...
end if
Why can't i change obj.Property without it changing the same property in comparisonObj.Property?

You are probably setting "comparisonObj = obj". You probably want "comparisonObj = obj.Clone()". You will have to implement the "Clone" method yourself.
If CMS_Page is not under your control, then you can create an extension method to clone it.

obj = db.CMS_Pages.First(Function(s) s.PageID = pageID)
comparisonObj = db.CMS_Pages.First(Function(s) s.PageID = pageID)
These two lines result in two references to the same object. Hence, when you do this: obj.property = sometextfield.text then comparisonObj will also reflect that change.

What is the result of
obj.ReferenceEquals(comparisonObj)
if that is True then obj is comparisonObj. You can do the same check more concisely like this,
obj Is comparisonObj
If you have a VB background, both variables are references to the same object.
If you have a C background, both variables are pointers to the same object.
essentially, the variable holds an integer value that addresses the object in memory.

Related

adding/removing objects to a list in vb.net

i have a list of objects called gobletinv that i want to add and remove objects from
right now to add a new object I've just done this
gobletinv(gobletpointer).mainstattype = MST.Text
gobletinv(gobletpointer).mainstatvalue = MSV.Text
gobletinv(gobletpointer).substat1type = ST1.Text
gobletinv(gobletpointer).substat1value = SV1.Text
gobletinv(gobletpointer).substat2type = ST2.Text
gobletinv(gobletpointer).substat2value = SV2.Text
gobletinv(gobletpointer).substat3type = ST3.Text
gobletinv(gobletpointer).substat3value = SV3.Text
gobletinv(gobletpointer).substat4type = ST4.Text
gobletinv(gobletpointer).substat4value = SV4.Text
gobletpointer += 1
i currently have no idea how i would remove an object from this list
Let's assume that the type your collection holds is called Stat. Let's also assume that gobletpointer is an Integer with an initial value of 0.
Each line where you are referencing the collection, you start it off with:
gobletinv(gobletpointer)
What this does is get the item from the collection at a given index.
So right now when you set the various property values to their respective TextBox value, you are overwriting the existing item in the collection.
If you wanted to add a new item to the collection, you would use the Add method (documentation). For example:
gobletinv.Add(New Stat() With {
mainstattype = MST.Text,
mainstatvalue = MSV.Text
substat1type = ST1.Text,
substat1value = SV1.Text,
substat2type = ST2.Text,
substat2value = SV2.Text,
substat3type = ST3.Text,
substat3value = SV3.Text,
substat4type = ST4.Text,
substat4value = SV4.Text
})
Now if you wanted to remove the object from the collection, it depends on how you want to remove it. But here is an example of leveraging the RemoveAt method (documentation) to remove the first record from the collection:
gobletinv.RemoveAt(0)
Update: This is a fiddle demonstrating how to add/remove items to the collection. https://dotnetfiddle.net/c0W6yS

Setting a variable to linq query with no results

I have a table that holds links to websites about particular theaters. I want to retrieve the first link for a given theater. My code to set the variable:
Dim link As String = TheaterLinks.Where(Function(x) x.TheaterID = TheaterID).FirstOrDefault().Link
If there are no results (some theaters won't have any links), then I get:
Object reference not set to an instance of an object.
How do I do this? I tried:
Dim link As String = Links.Where(Function(x) x.TheaterID = TheaterID.DefaultIfEmpty().First().Link
But I can't figure out what to put inside DefaultIfEmpty(). I tried DefaultIfEmpty("") and DefaultIfEmpty(blankstringvariable) but then I get:
Value of type 'String' cannot be converted to type 'TheaterLink'.
The problem is that FirstOrDefault() is allowed to return null, in which case accessing Link property would throw an exception.
If you use VB.NET 14, add question mark for automatic null checking:
Dim link As String = TheaterLinks.Where(Function(x) x.TheaterID = TheaterID).FirstOrDefault()?.Link
(see ?.Link instead of .Link)
Otherwise, do it in two stages: first, get the object using FirstOrDefault, then null-check it manually with an If statement.
For my original example, I just had to add a question mark:
Dim link As String = Links.Where(Function(x) x.ID = id).FirstOrDefault()?.Link
I tried doing this in my model and got a "Nullable object must have a value" error, so I did the two-stage approach:
Dim eventDate = Events.Where(Function(x) x.ID = id).FirstOrDefault()?.EventDate
If eventDate.HasValue Then
'some code
Else
'some code
End If

Pass array has object property from foxpro (to c#)

I'm trying to have a class that hold a array and use that class in some COM calls (I makes using C#).
So, I've got my classes like this:
DEFINE CLASS Logistics_Columns AS Session OLEPUBLIC
DIMENSION COLUMNS_ARRAY[1]
DIMENSION COLUMNS_ARRAY_COMATTRIB(4)
COLUMNS_ARRAY_COMATTRIB(1) = 0
COLUMNS_ARRAY_COMATTRIB(2) = "COLUMNS_ARRAY"
COLUMNS_ARRAY_COMATTRIB(3) = "COLUMNS_ARRAY"
COLUMNS_ARRAY_COMATTRIB(4) = "Array"
ENDDEFINE
DEFINE CLASS Logistics_Column AS Session OLEPUBLIC
COLUMN_NAME = .NULL.
DIMENSION COLUMN_NAME_COMATTRIB(4)
COLUMN_NAME_COMATTRIB(1) = 0
COLUMN_NAME_COMATTRIB(2) = "COLUMN_NAME"
COLUMN_NAME_COMATTRIB(3) = "COLUMN_NAME"
COLUMN_NAME_COMATTRIB(4) = "Character"
COLUMN_TYPE = .NULL.
DIMENSION COLUMN_TYPE_COMATTRIB(4)
COLUMN_TYPE_COMATTRIB(1) = 0
COLUMN_TYPE_COMATTRIB(2) = "COLUMN_TYPE"
COLUMN_TYPE_COMATTRIB(3) = "COLUMN_TYPE"
COLUMN_TYPE_COMATTRIB(4) = "Character"
COLUMN_WIDTH = .NULL.
DIMENSION COLUMN_WIDTH_COMATTRIB(4)
COLUMN_WIDTH_COMATTRIB(1) = 0
COLUMN_WIDTH_COMATTRIB(2) = "COLUMN_WIDTH"
COLUMN_WIDTH_COMATTRIB(3) = "COLUMN_WIDTH"
COLUMN_WIDTH_COMATTRIB(4) = "Integer"
COLUMN_PRECISION = .NULL.
DIMENSION COLUMN_PRECISION_COMATTRIB(4)
COLUMN_PRECISION_COMATTRIB(1) = 0
COLUMN_PRECISION_COMATTRIB(2) = "COLUMN_PRECISION"
COLUMN_PRECISION_COMATTRIB(3) = "COLUMN_PRECISION"
COLUMN_PRECISION_COMATTRIB(4) = "Integer"
ENDDEFINE
In C# for the Logistics_Columns class, COLUMNS_ARRAY is not seen as an array.
Yet or the Logistics_Column class all 4 properties are correctly seen as string or integer.
I guess "Array" (COLUMNS_ARRAY_COMATTRIB(4) = "Array")isn't the right literal value to indicate an array.
But then, what is?
As planned I created a custom collection wrapper.
It's basically a foxpro class of type Session OLEPUBLIC which store a Collection and wraps its methods.
Regarding the performance I think it adds some noticeable overhead, but it's the best method I could eventually come with.

Matlab's arrayfun for uniform output of class objects

I need to build an array of objects of class ID using arrayfun:
% ID.m
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
obj.id = id;
end
end
end
But get an error:
>> ids = 1:5;
>> s = arrayfun(#(id) ID(id), ids)
??? Error using ==> arrayfun
ID output type is not currently implemented.
I can build it alternatively in a loop:
s = [];
for k = 1 : length(ids)
s = cat(1, s, ID(ids(k)));
end
but what is wrong with this usage of arrayfun?
Edit (clarification of the question): The question is not how to workaround the problem (there are several solutions), but why the simple syntax s = arrayfun(#(id) ID(id), ids); doesn't work. Thanks.
Perhaps the easiest is to use cellfun, or force arrayfun to return a cell array by setting the 'UniformOutput' option. Then you can convert this cell array to an array of obects (same as using cat above).
s = arrayfun(#(x) ID(x), ids, 'UniformOutput', false);
s = [s{:}];
You are asking arrayfun to do something it isn't built to do.
The output from arrayfun must be:
scalar values (numeric, logical, character, or structure) or cell
arrays.
Objects don't count as any of the scalar types, which is why the "workarounds" all involve using a cell array as the output. One thing to try is using cell2mat to convert the output to your desired form; it can be done in one line. (I haven't tested it though.)
s = cell2mat(arrayfun(#(id) ID(id), ids,'UniformOutput',false));
This is how I would create an array of objects:
s = ID.empty(0,5);
for i=5:-1:1
s(i) = ID(i);
end
It is always a good idea to provide a "default constructor" with no arguments, or at least use default values:
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
if nargin<1, id = 0; end
obj.id = id;
end
end
end

Instantiate class from name in MATLAB

I'm trying to list classes I created in some folder in my Matlab folder - using only their name (class name)
as an example, I have a class called 'SimpleString' - and I'm aiming to instantiate an object from that class, if all I know is that its name is 'SimpleString'
So in realtime, I'd like to find out what classes are in a folder (done), then be able to instantiate any of those classes (my question)
Thanks
Use a package to access class constructors with .()-notation.
A Matlab package is simply a folder/directory with a name that begins with +:
+mypackage/foo.m:
classdef foo
methods
function obj = foo(arg1, arg2)
%foo constructor
end
end
end
With class foo defined this way, you can access the constructor of mypackage.foo as
class_name = 'foo';
o = mypackage.(class_name)('arg1_value', 'arg2_value');
Use str2func to get a function handle to the constructor. You can then call it with whatever arguments are appropriate.
>> m = str2func('containers.Map')
m =
#containers.Map
>> x = m({'foo', 'bar'}, {0, 1})
x =
containers.Map handle
Package: containers
Properties:
Count: 2
KeyType: 'char'
ValueType: 'double'
Methods, Events, Superclasses
You can use the WHAT function to discover classes (as well as functions,packages,etc...) in a certain folder, then call METHODS to find the signature of the constructor of the class (some parsing needed here), finally using FEVAL (passing arguments if any) to create an object from this class.
You could also use meta.class to get all sorts of meta-information about your classes.
EDIT
Here is some code to illustrate what I had in mind:
%# folder containing your classes
pathName = fullfile(pwd,'folder');
%# make sure it is on the path
p = textscan(path, '%s', 'Delimiter',';'); p=p{1};
if ~any(ismember(p,pathName))
addpath(pathName)
end
%# list MATLAB files
w = what(pathName);
%# get class names
fNames = cellfun(#(s) s(1:end-2), w.m, 'Uni',false); %# remove .m extension
fNames = [fNames ; w.classes]; %# add classes in #-folders
%# get classes metadata
mt = cellfun(#meta.class.fromName, fNames, 'Uni',false); %# get meta-data
mt = mt( ~cellfun(#isempty,mt) ); %# get rid of plain functions
%# build object from each class
objects = cell(numel(mt),1);
for i=1:numel(mt)
%# get contructor function
ctorMT = findobj(mt{i}.MethodList, 'Access','public', 'Name',mt{i}.Name);
%# get number of contructor arguments
numArgs = numel(ctorMT.InputNames);
%# create list of arguments (using just zeros)
args = repmat({0}, [numArgs 1]);
%# create object
try
obj = feval(ctorMT.Name,args{:});
catch ME
warning(ME.identifier, ME.message)
obj = [];
end
%# store object
objects{i} = obj;
end
As you can see, I found it easier to simply use meta.class to get metadata about the classes, instead of manually parsing the output of methods('fcn','-full') as I originally suggested.
However this is not perfect, as there is no way to find out what type of input each constructor expect (only how many). I opted to always pass 0 for each argument..
To test the implementation above, I create these sample classes (one in a self-contained file, the other defined in #-folder with multiple files):
folder/hello.m
classdef hello
properties
name = '';
end
methods
function this = hello()
this.name = 'world';
end
function val = get.name(obj)
val = obj.name;
end
function obj = set.name(obj,val)
obj.name = val;
end
function say(obj)
fprintf('Hello %s!\n',obj.name);
end
end
end
folder/#hello2/hello2.m
classdef hello2
properties
name
end
methods
function this = hello2(val)
this.name = val;
end
function val = get.name(obj)
val = obj.name;
end
function obj = set.name(obj,val)
obj.name = val;
end
end
methods
say(obj)
end
end
folder/#hello2/say.m
function say(obj)
fprintf('Hello2 %s!\n', obj.name);
end
You can use eval to instantiate the class using just the class name.
instance = eval('SimpleString');
However, if you're simply iterating through all the m-files in a folder containing class definitions and grabbing the file names, you'll only be able to invoke the default constructor using this method.