Implementing an hgsetget subclass
Mostrar comentarios más antiguos
>>u=unit('SI');
>>set(u) % set behavior 1
System: '[{SI} | cgs]'
>>set(u,'System') % set behavior 2
[{SI} | cgs]
>>set(u,'System','cgs') % set behavior 3
>>get(u,'System')
ans =
cgs
In other words, much like the behavior you see for a figure handle. Following the example in Implementing a Set/Get Interface for Properties, I tried this code:
classdef unit < hgsetget
properties
System = '';
end
methods
function H = unit(str)
if nargin > 0
H.System = str;
end
end
function H = set.System(H,str)
H.System = str;
end
end
end
This gets set behavior 3 right, but how do I add the other two? The closest I have come so far is to simply program all the cases into an overloaded set method, and get rid of set.System. But if I add a few more properties, this gets quite ugly. Does anyone know an elegant way of doing this?
Respuesta aceptada
Más respuestas (3)
Jiro Doke
el 26 de Feb. de 2011
This is interesting. It does seem like the documentation isn't complete. It mentions how calling the set with a particular syntax returns the possible values of a property, but it doesn't explain how to specify those possible values.
Here's something that I put together to try to achieve what you want, while making it somewhat extensible to multiple properties:
classdef MyClass < hgsetget
properties
Prop1
Prop2
end
properties (Hidden, Constant)
Prop1_values = {'SI', 'cgs'}
Prop2_values = {'C', 'F'}
end
methods
function varargout = set(obj, varargin)
% Allow only one output and no more than 3 input arguments
error(nargoutchk(0, 1, nargout, 'struct'));
error(nargchk(1, 3, nargin, 'struct'));
switch nargin
case 1 % set(h) syntax
propnames = properties(obj);
if nargout
s = cell2struct(cell(size(propnames)), ...
propnames, 1);
for id = 1:length(propnames)
s.(propnames{id}) = set(obj, propnames{id});
end
varargout{1} = s;
else
for id = 1:length(propnames)
set(obj, propnames{id});
end
end
case 2 % set(h, 'PropertyName') syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
if nargout
varargout{1} = MyClass.([varargin{1}, '_values']);
else
fprintf('%10s: %s\n', varargin{1}, ...
toString(MyClass.([varargin{1}, '_values'])));
end
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
case 3 % set(h, 'PropertyName', value) syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
val = validatestring(varargin{2}, ...
MyClass.([varargin{1}, '_values']), ...
mfilename, varargin{1});
obj.(varargin{1}) = val;
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
if nargout
varargout{1} = [];
end
end
end
end
end
function str = toString(in)
in{1} = ['{', in{1}, '}']; % first input is the default
str = sprintf('| %s ', in{:});
str = ['[', str(2:end), ']'];
end
I have Hidden, Constant properties that specify the possible property values, and the set method queries that information. So whenever I create a new property, I create a corresponding Prop#_values property.
EDIT: I've implemented a Setter for the properties. In this example, instead of creating a separate Setter method for each property, I made it as a part of the set method (see case 3 in the switch statement). Since the Prop#_values contain the valid string values, I use that to validate the input.
Test...
>> a = MyClass;
>> set(a)
Prop1: [ {SI} | cgs ]
Prop2: [ {C} | F ]
>> set(a, 'Prop2')
Prop2: [ {C} | F ]
>> set(a, 'Prop1', 'cgs')
>> get(a, 'Prop1')
ans =
cgs
>> set(a, 'Prop2', 'CF')
??? Error using ==> MyClass
Expected Prop2 to match one of these strings:
C, F
The input, 'CF', did not match any of the valid strings.
Error in ==> MyClass>MyClass.set at 46
val = validatestring(varargin{2}, ...
>>
7 comentarios
Andrew Newell
el 26 de Feb. de 2011
Jiro Doke
el 26 de Feb. de 2011
@Andrew: I modified my answers to include set validation. Instead of creating a separate setter method, I do it inside the "set" method. I use Prop#_value property to validate the input.
I see your question about the advantage of using hgsetget. I honestly don't know, and I'm asking around to see if someone has a good explanation. I'll post here once I hear something.
Andrew Newell
el 26 de Feb. de 2011
Jiro Doke
el 26 de Feb. de 2011
@Andrew: Yes, I would normally use set.Prop methods for each method. In this case, I assumed all the properties accept only strings from a cell array of strings. So I put it all in the set method.
"validatestring" is only for selecting from a selection of strings. You may also want to look at "validateattributes".
Andrew Newell
el 27 de Feb. de 2011
Jiro Doke
el 28 de Feb. de 2011
@Andrew: That's great! Would you care to share that on the File Exchange? It seems like there is no simple way of doing it with HGSETGET, so your approach might be the best currently.
Andrew Newell
el 28 de Feb. de 2011
Andrew Newell
el 25 de Feb. de 2011
Andrew Newell
el 10 de Mzo. de 2011
0 votos
Categorías
Más información sobre Argument Definitions en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!