Problem
- Converting IValueSet results to enumerations
Proposal
Additions to Standard
interface IExchangeAdaptor
{
IExchangeItem ExchangeItemOriginal { set; get; }
IExchangeItem ExchangeItemNew { get; }
object Adapt(IValueSet value);
}
// Optional Extension for ILinkableComponent
interface IExchangeAdaptable
{
int SuggestedAdaptorsCount { get; }
IExchangeAdaptor AdaptorSugestion(int index);
}
Optional change to Standard
class ILinkableComponent
{
......
object GetValues(ITime time, string linkID);
......
}
Example
Enumeration
enum ReedGrowth { High = 0, Medium, Low, }
Example of it working
static void Adaptors()
{
ITime time = new TimeStamp(10.0);
string linkid = "wibble";
// has an output exchange item which returns Reed Growth as a height (IScalar/double)
ILinkableComponent iLC = new LinkableComponentReedGrowth();
IValueSet vs = iLC.GetValues(time, linkid);
double d = ((IScalarSet)vs).GetScalar(0);
string id = iLC.GetOutputExchangeItem(0).Quantity.ID;
string idd = iLC.GetOutputExchangeItem(0).Quantity.Description;
// make 3rd party Linkable component adaptable
LinkableComponentAdaptable iLCA = new LinkableComponentAdaptable(iLC);
// change Reed Growth to an enum ReedGrowth { High = 0, Medium, Low, }
int index = iLCA.MakeAdaption("ReedGrowthHeight", new ReedGrowthEnum());
ReedGrowth growth = (ReedGrowth)iLCA.GetValuesAdapted(time, linkid);
string ida = iLCA.GetOutputExchangeItem(index).Quantity.ID;
string idda = iLCA.GetOutputExchangeItem(index).Quantity.Description;
// Another proposed change:
// object GetValues(time, linkid, out bool adapted);
// if adapted false then IValueSet returned, else user needs to test against 'as' ie ...
object o = iLCA.GetValuesAdapted(time, linkid);
if (o is ReedGrowth)
{
ReedGrowth gr = (ReedGrowth)o;
bool badGrowth = gr == ReedGrowth.High;
}
}
Wrapped LinkableComponent to allow Adaption
class LinkableComponentAdaptable : ILinkableComponent
{
// Redirect to aggregated linkiable component all members ....
#region ILinkableComponent Members
#region IPublisher Members
// ... except ....
public LinkableComponentAdaptable(ILinkableComponent iLC)
{
_iLC = iLC;
}
public int OutputExchangeItemCount
{
get { return _iLC.OutputExchangeItemCount; }
}
public IOutputExchangeItem GetOutputExchangeItem(int index)
{
IOutputExchangeItem item = _iLC.GetOutputExchangeItem(index);
if (_adaptedExchangeItems.ContainsKey(item))
return (IOutputExchangeItem)_adaptedExchangeItems[item].ExchangeItemNew;
return item;
}
public IValueSet GetValues(ITime time, string linkID)
{
return _iLC.GetValues(time, linkID);
}
public object GetValuesAdapted(ITime time, string linkID)
{
IValueSet vs = _iLC.GetValues(time, linkID);
/*
* from linkid get iLink
* from iLink get sourceComponent
* from iLink get sourceQuantity.ID
* fudged below ....
*/
ILinkableComponent iSource = this; // fudge
string sourceQID = "ReedGrowthHeightEnum"; // fudge
int index = -1;
for (int n = 0; n < iSource.OutputExchangeItemCount; ++n)
{
if (iSource.GetOutputExchangeItem(n).Quantity.ID == sourceQID)
index = n;
}
if (index > -1)
{
IOutputExchangeItem item = _iLC.GetOutputExchangeItem(index);
if (_adaptedExchangeItems.ContainsKey(item))
return _adaptedExchangeItems[item].Adapt(vs);
}
return vs;
}
// New Members
public int MakeAdaption(string quantityId, IExchangeAdaptor adaptor)
{
for (int n = 0; n < OutputExchangeItemCount; ++n)
{
if (GetOutputExchangeItem(n).Quantity.ID == quantityId)
{
adaptor.ExchangeItemOriginal = GetOutputExchangeItem(n);
_adaptedExchangeItems.Add(GetOutputExchangeItem(n), adaptor);
return n;
}
}
return -1;
}
Dictionary<IOutputExchangeItem, IExchangeAdaptor> _adaptedExchangeItems = new Dictionary<IOutputExchangeItem, IExchangeAdaptor>();
ILinkableComponent _iLC;
}
Quantity for Reed Growth Enumeration
class QuantityAsEnum : IQuantity
{
IQuantity _quantity;
public QuantityAsEnum(IQuantity q)
{
_quantity = q;
}
#region IQuantity Members
public string ID
{
get { return _quantity.ID + "Enum"; }
}
public string Description
{
get { return _quantity.Description + " Adapted to enumeration return value"; }
}
public org.OpenMI.Standard.ValueType ValueType
{
get { return _quantity.ValueType; }
}
public IDimension Dimension
{
get { return _quantity.Dimension; }
}
public IUnit Unit
{
get { return _quantity.Unit; }
}
#endregion
}
Adapter to make Reed Growth an enum
class ReedGrowthEnum : IExchangeAdaptor
{
double _high = 15;
double _low = 5;
IExchangeItem _original;
IExchangeItem _new;
#region IAdaptor Members
public object Adapt(IValueSet value)
{
ReedGrowth rg = ReedGrowth.Medium;
double d = ((IScalarSet)value).GetScalar(0);
if (d > _high)
rg = ReedGrowth.High;
if (d < _low)
rg = ReedGrowth.Low;
return rg;
}
public IExchangeItem ExchangeItemOriginal
{
set
{
_original = value;
if (value is IInputExchangeItem)
_new = new InputExchangeItem(new QuantityAsEnum(_original.Quantity), _original.ElementSet);
else if (value is IOutputExchangeItem)
_new = new OutputExchangeItem(new QuantityAsEnum(_original.Quantity), _original.ElementSet);
else
{
Debug.Assert(false);
}
}
get { return _original; }
}
public IExchangeItem ExchangeItemNew
{
get { return _new; }
}
#endregion
}
Original LinkableComponent with Reed Growth as a double
class LinkableComponentReedGrowth : ILinkableComponent
{
#region ILinkableComponent Members
#region IPublisher Members
public int OutputExchangeItemCount
{
get { return 1; }
}
public IOutputExchangeItem GetOutputExchangeItem(int index)
{
return index == 0 ? _reeds : null;
}
public IValueSet GetValues(ITime time, string linkID)
{
return new Double(12);
}
ReedGrowthHeight _reeds = new ReedGrowthHeight();
}
Reed growth as double Output Exchange Item
class ReedGrowthHeight : IOutputExchangeItem
{
#region IOutputExchangeItem Members
#region IExchangeItem Members
public IQuantity Quantity
{
get { return _quantity; }
}
public IElementSet ElementSet
{
get { return null; }
}
#endregion
ReedGrowthQuantity _quantity = new ReedGrowthQuantity();
}
Reed Growth as double Quantity
class ReedGrowthQuantity : IQuantity
{
#region IQuantity Members
public string ID
{
get { return "ReedGrowthHeight"; }
}
public string Description
{
get { return "ReedGrowthHeight as a scalor"; }
}
public org.OpenMI.Standard.ValueType ValueType
{
get { return org.OpenMI.Standard.ValueType.Scalar; }
}
public IDimension Dimension
{
get { return null; }
}
public IUnit Unit
{
get { return null; }
}
#endregion
}
Util to give me a IScalerSet from a double
class Double : IScalarSet
{
double _double;
public Double(double d)
{
_double = d;
}
#region IScalarSet Members
public double GetScalar(int index)
{
return IsValid(index) ? _double : -999.999;
}
#endregion
#region IValueSet Members
public int Count
{
get { return 1; }
}
public bool IsValid(int index)
{
return index == 0;
}
#endregion
}
1 Comment
Unknown User (don)
20-10-2007Looks complicated.
How I'd expect it to be used when it is necessary to convert values and not exchange items. For example to convert values from exchange item containing value as a string to value in exchange item wrapping enum-type values:
class StringValueTypeExchangeItem : IExchangeItem { String v; object Value { get { return v; } set { v = (String)value; } } } // this class returns value from connected exchange item if it is defined (provider). class EnumValueTypeExchangeItem : IExchangeItem { IExchangeItem provider; // not null if this exchange item is connected somewhere MyCustomEnum v; // returns value from connected exchange item if it is defined public object Value { get { if(provider!= null) { return provider.Value; } else { return v; } } set { ... } } } class ValueTransformationTests { void TransformExchangeItemValuesFromStringToEnum() { // get these exchange items somewhere StringValueTypeExchangeItem src = ...; EnumValueTypeExchangeItem dst = ...; // make sure value types in Quantities are ok Assert.AreEqual(src.Quantity.ValueType, typeof(String)); Assert.AreEqual(dst.Quantity.ValueType, typeof(MyCustomEnum)); /* Create component containing 2 exchange items: src => InputExchangeItem ---<> ValueConvertorComponent <>--- OutputExchangeItem => dst */ IComponent valueConvertor = ...; valueConvertor.InputItem[0].ConnectFrom(src); valueConvertor.OutputItem[0].ConnectTo(dst); // here valueConvertor component will return value converted from string to enum! // user will not notice it, everything will happen automatically on-the-fly MyCustomEnum value = (MyCustomEnum)dst.Value; } }