WARNING: This is an HTML post, for the sake of readability, if your client can see HTML posts, do it, it doesn't contain any script or virus
![Smile :-) :-)](/styles/default/custom/smilies/smile.gif)
I can reformat a non-HTML post if you want me to (and if this doesn't see correctly with non-HTML viewers)
Ok, I'm fed up with this so I'll explain the situation here and my approach (which sucks), and see if anyone can give a better solution to this.
I'm making a way to have several parameters of a class (a instance of a class) accesed via strings (for a script system)... I don't want to use the default property collections in C# because: 1) that'd give me access to all public properties/member variables, and that's not what I want, and 2) that'd not be easy to manage from other languages.
So that doesn't count as an option.
My current approach is:
- I have an interface IScriptable, where I define some methods that all classes with accesable as scripting components will have (basically, a function that will set the parameters and associated values)
- I have a base class, CScriptableObject (which implements IScriptable) with the basic implementation of this class, with no parameters. Rests of the classes will derive from this, and override certain methods.
- Let me make an example of a CScripttableObject derived class:
/*
Color Chart (for those of you with an HTML-viewer for usenet:
Blue: normal 'blue' stuff in Visual Studio.Net
Green: Comments
Purple: Variables that will be accessed from the Scripting Engine
Red: Name of the variables in the script (example, in a script, var1 will access variable1)
Black: Rest of the code
*/
public class MyScriptableClass : CScriptableObject
{
public MyType variable1, variable2;
private OtherType someMoreVariables;
// This is overriden from the CScriptableObject's one
public override void InitializeMembers()
{
base.InitializeMembers(); // We'll call the parent class first, just in case
// initialization of variables
someMoreVariables = new OtherType();
variable1 = new MyType();
variable2 = new MyType();
}
// This is overriden from the CScriptableObject's one
public override void SetObjectInfo()
{
ScriptObject = new ScriptObjectInfo
( "MyTypeClass", // String name for this class type [for the scripting engine]
new ScriptParameter("var1", ref variable1), // We set a parameter, named "var1", referencing variable1
new ScriptParameter("var2", ref variable2) // We set a parameter, named "var2", referencing variable2
);
}
// [etc...]
}
Ok, so now we have that we have a class "MyType", with 2 script-accesible variables, "variable1" and "variable2". The script-name for the class type will be "MyTypeClass", and the variable names (for the script) are "var1" and "var2". There are other variables in the class (someMoreVariables) which are not accesible through the script (as they are not defined for the script in the ScriptObjectInfo).
Now in the base CScriptableObjects I have some methos to retrieve parameters.
Ok, I had this implemented in C++, using pointers and stuff, and there was not a single problem with it. Now I've come to this problem in C#
I can use a reference to reference-types, or "boxed" value-types, and store it in an "object" class. HOWEVER:
- If I ever assign (within the class) a value to the value-type, the reference is referencing a copy, thus doesn't get updated:
Example:
CORRECT
-------
int i = 5;
object o = (object)i;
o = 10;
Console.Write("{0},{1}",i,(int)o);
Result: 10, 10
INCORRECT
---------
int i = 5;
object o = (object)i;
i = 10;
Console.Write("{0},{1}",i,(int)o);
Result: 10, 5
I can understand why this happens though, when I do "i = 10", the compiler is internally doing "i = new System.Int32(10)", so the reference gets lost, as it's allocating new memory.
Now there are only two workarounds for this:
1) Make a wrapper class for value types.
This leads me to two problems:
- You can't overload operator =, and the only way to do it is setting an implicit operator, for example:
public static implicit operator CIntParameter(int val)
{
return new CIntParameter(val);
}
- That'd allow me to do:
CIntParameter i = 10;
However, that creates a new object anyway, so the reference would get lost anyway. Thus, the only way to do it is using a Get() and Set() parameters so that it returns or sets the int value within my CIntParameter.
That is, for one, a pain in the ass to program with (not being able to use "="), and for two, error-prone, because I could be misusing the = operator at some point (with another CIntParameter) and it would assign the reference of the other, so the original parameter reference would get lost.
2) Go unsafe and use pointers for everything... but I'd be using Unamanged C++ if I was to do that, right?
So, any of you know of any different approach to this problem, or can think of a better solution? (or been there?)
In conclusion, all of these Value-Types and Reference-Types deriving from the same System.Object is stupid IMHO, but the fact that you can't overload operator =, or you can't just assign a reference which the system could be tracing for value-types (it's tracing it with the garbage collector whenever you change a reference, so that it knows if the object is referenced by any other thing, and if it's not, dispose it, it could be easy for the CLR to reassign a reference, maybe using another different keyword). Or you could just have CLR-optimized reference-types for basic values (ref int, ref double, or something like that).
I hope I'm not being wrong with all of this, if I am, please someone explain it to me, and tell me how to handle this case. Hope I've explained myself clear.
Thank you very much for the long reading, and sorry for the HTML, those of you who can't see it. I can reformat a non-HTML post if you want me to (and if this doesn't see correctly with non-HTML viewers)
Javier Campos
Virtual Media Systems, S.L.