Пример #1
0
        /// <summary>Initializes a new field, or overwrites an existing one. Can optionally be typed strongly.</summary>
        /// <param name="fieldName">The field to be added</param>
        /// <param name="values">IEnumerable containing </param>
        /// <param name="type"></param>
        /// <exception cref="ParseFormularException">This exception is thrown if the fieldName contains invalid characters.</exception>
        /// <exception cref="EmptyBinException">This exception is thrown if values is or contains null.</exception>
        /// <exception cref="InvalidCastException">This exception is thrown if a value is added to a bin that cannot be cast to the bin's type.</exception>
        /// <exception cref="BinTypeMismatchException">This exception is thrown if a value is added to a bin that cannot be cast to the bin's type.</exception>
        /// <exception cref="TypeNotSupportedException">This exception is thrown if the new bin's type is not registered in TypeIdentity.</exception>
        /// <exception cref="ArgumentNullException">This exception is thrown if attempt is made to add null to a the bin.</exception>
        public void AssignFrom(string fieldName, IEnumerable values, Type type = null)
        {
            if (!fieldName.IsValidFieldName())
            {
                throw new ParseFormularException("\"" + fieldName + "\" is not a valid name for a Message's field. Only use alphanumerics, dots, hyphens and underscores. ");
            }

            if (type == null)
            {
                if (values == null)
                {
                    throw new ArgumentNullException("Attempted to Assign null to a new Bin.");
                }

                var gen = values.GetType().GenericTypeArguments;

                // in case en is not generic, pick the first one and reflect
                if (gen == null || gen.Count() != 1)
                {
                    var tmp = values.Cast <object>(); // throws ArgumentNullException and InvalidCastException.

                    if (tmp.Count() == 0)
                    {
                        throw new EmptyBinException("Cannot add an empty bin without information about its type. Consider adding type information to AssignFrom()");
                    }

                    var obj = tmp.FirstOrDefault();

                    if (obj == null)
                    {
                        throw new ArgumentNullException("Cannot assign null to a new Bin.");
                    }
                    type = obj.GetType();
                }
                else
                {
                    type = values.GetType().GenericTypeArguments[0];
                }
            }

            type = TypeIdentity.Instance.FindBaseType(type); // break it down.
            if (type == null)
            {
                throw new TypeNotSupportedException("The assignment for the Field [" + fieldName + "] failed, type is not supported: " + this.Topic);
            }

            // replace if type does not match
            if (!Data.ContainsKey(fieldName) || type != Data[fieldName].GetInnerType())
            {
                Data.Remove(fieldName);
                Data.Add(fieldName, BinFactory.New(type));
            }
            else
            {
                Data[fieldName].Clear();
            }

            Data[fieldName].Add(values); // implicit conversion
        }
Пример #2
0
        /// <summary>Deep Clones the given Message. Fields of type Message will not be deep cloned.</summary>
        /// <returns>A new Message</returns>
        public object Clone()
        {
            // might be faster when utilizing binary serialisation.

            Message m = new Message();

            m.Topic     = Topic;
            m.TimeStamp = TimeStamp;

            foreach (string name in Data.Keys)
            {
                var list    = Data[name];
                var type    = list.GetInnerType();
                var newList = BinFactory.New(type, list.Count);

                // deep cloning of all fields, but messages: nested messages are merely a reference by design.
                bool isPrimitiveType = type.IsPrimitive || type.IsValueType || (type == typeof(string));

                if (isPrimitiveType || type == typeof(Message))
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        newList.Add(list[i]); // if primitive -> auto copy. if Message -> reference only
                    }
                }
                else
                {
                    if (typeof(ICloneable).IsAssignableFrom(type))
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            var clone = ((ICloneable)list[i]).Clone();
                            newList.Add(clone);
                        }
                    }
                    else
                    {
                        throw new SystemException(type.FullName + " cannot be cloned nor copied, while cloning the message " + this.Topic);
                    }
                }

                m[name] = newList; // add list to new Message
            }
            return(m);
        }
Пример #3
0
        /// <summary>Deep Clones the given Message. Fields of type Message will not be deep cloned.</summary>
        /// <returns>A new Message</returns>
        public object Clone()
        {
            Message m = new Message();

            m.Topic     = Topic;
            m.TimeStamp = TimeStamp;

            foreach (string name in Data.Keys)
            {
                var list   = Data[name];
                var type   = list.GetInnerType();
                var newBin = BinFactory.New(type, list.Count);

                var typeRecord = TypeIdentity.Instance[type];

                if (typeRecord == null)
                {
                    throw new SystemException(type.FullName + " is not a registered type. Cannot add such a field to Message \"" + this.Topic + "\"");
                }

                // removing this line will force creation of empty bins, if the field is not cloneable somehow.
                if (typeRecord.CloneMethod == CloneBehaviour.Null)
                {
                    continue;                                                // omit the entire Field
                }
                for (int i = 0; i < list.Count; i++)
                {
                    switch (typeRecord.CloneMethod)
                    {
                    case CloneBehaviour.Null:
                        continue;

                    case CloneBehaviour.Assign:
                        newBin.Add(list[i]);
                        break;

                    case CloneBehaviour.Clone:
                        var clone = (list[i] as ICloneable)?.Clone();
                        if (clone == null)
                        {
                            throw new SystemException(type.FullName + " cannot be cloned with IClone interface. Check Profile. " + this.Topic);
                        }
                        newBin.Add(clone);
                        break;

                    case CloneBehaviour.Custom:
                        var customClone = typeRecord.CustomClone(list[i]);
                        if (customClone == null)
                        {
                            throw new SystemException(type.FullName + " cannot be cloned with Custom Clone delegate. Check Profile. " + this.Topic);
                        }
                        newBin.Add(customClone);
                        break;

                    default: throw new NotImplementedException("CloneBehaviour " + typeRecord.CloneMethod.ToString() + " unhandled.");
                    }
                }

                m[name] = newBin; // add list to new Message
            }
            return(m);
        }
Пример #4
0
 public object Clone()
 {
     return(BinFactory.New(this as IEnumerable <T>));
 }