|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
Nullable types in ActionScript
by Tim Clem-2
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message We're trying to have near-seamless support for nullable types in
ActionScript, but we've hit a roadblock. Has anyone else solved this problem in an elegant way? We have four goals in mind: - Use the standard System.Nullable<T> type on the .Net side - As much type-safety as possible on the ActionScript side (i.e., few/no *-typed variables) - Since our entities often have many properties and inheritance, we'd like to stay away from custom IExternalizable implementations for them - A sentinel value (like the <nullable> config section) won't work because we don't know what (if any) value won't be used With these ideas in mind, we've come up with a solution that would work if a small change was made in FluorineFx.Util.Convert. I'll walk you through the idea and what would need to change. In ActionScript, we make small classes that act like .Net's Nullable<T> and implement IExternalizable in a sensible way. The setter on the Value property is untyped to allow it to be assigned to null, the actual data type, or the nullable type. For instance, here's NullableBoolean: import flash.errors.IllegalOperationError; import flash.utils.IDataInput; import flash.utils.IDataOutput; import flash.utils.IExternalizable; [RemoteClass(alias="ServiceLibrary.NullableBoolean")] public class NullableBoolean implements IExternalizable { private var _Value:Boolean; public function get Value():Boolean { if(!HasValue) throw new IllegalOperationError("The object has no value"); return _Value; } public function set Value(val:*):void { if(val == null) _HasValue = false; else if(val is Boolean) { _Value = val; _HasValue = true; } else if(val is NullableBoolean) { var ni:NullableBoolean = NullableBoolean(val); if(ni.HasValue) _Value = ni.Value; else _HasValue = false; } else throw new TypeError("The given value is not of an appropriate type"); } private var _HasValue:Boolean; public function get HasValue():Boolean { return _HasValue; } public function NullableBoolean(val:* = null) { Value = val; } public function readExternal(input:IDataInput):void { Value = input.readObject() as Boolean; } public function writeExternal(output:IDataOutput):void { output.writeObject(HasValue ? Value : null); } } Now, on classes that have nullable members, we use this type like so: [RemoteClass(alias="ServiceLibrary.ObjectWithNullableBool")] public class ObjectWithNullableBool { private var _PossibleBool:NullableBoolean = new NullableBoolean(); public function get PossibleBool():NullableBoolean { return _PossibleBool; } public function set PossibleBool(val:*):void { _PossibleBool.Value = val; } } Since we just pass through the assignment, we can assign to PossibleBool with null, a Boolean, or another NullableBoolean. Now, on the .Net side, there's a counterpart to the NullableBoolean type that's really just a proxy for Nullable<Boolean> with an IExternalizable and IConvertible implementation: [Serializable] internal struct NullableBoolean: IExternalizable, IConvertible { public Nullable<Boolean> Value { get; private set; } void IExternalizable.ReadExternal(IDataInput input) { Value = (Nullable<Boolean>)input.ReadObject(); } void IExternalizable.WriteExternal(IDataOutput output) { if (Value.HasValue) output.WriteObject(Value); output.WriteObject(null); } // Unimplemented IConvertible members omitted bool IConvertible.ToBoolean(IFormatProvider provider) { return (bool)Value; } } This is where we hit the problem. Fluorine eventually tries to convert our NullableBoolean type to a Nullable<Boolean> using FluorineFx.Convert.ToNullableBoolean(object). This function (and its versions for different types) has a very specific idea about what is null: if (value == null || value is DBNull) return null; Since the value variable is of type object at this time, the == operator is the one from System.Object, which we can't override. So, we have no way to tell Fluorine when our NullableBoolean type is actually holding a null. To remedy this, I suggest that the check above (and in all the Convert.ToNullableType(object) functions) be modified to understand the System.Data.SqlTypes.INullable interface. That way we could just add the code below to NullableBoolean and have a pretty seamless nullable implementation: [Transient] bool INullable.IsNull { get { return !Value.HasValue; } } Sound reasonable? The only drawback I can see is that INullable doesn't have any information about the underlying type, so the modified Convert functions would convert any INullable type reporting IsNull to any other nullable type. That's an issue with DBNull as well, really. Or, perhaps this is going way overboard and there's an easier solution. Thoughts? --Tim Clem RIA Developer, Stream57 _______________________________________________ fluorine mailing list fluorine@... http://fluorine.thesilentgroup.com/mailman/listinfo/fluorine_fluorine.thesilentgroup.com |
| Free embeddable forum powered by Nabble | Forum Help |