Work on source code documentation (mostly complete).
[lwes-dotnet/github-mirror.git] / Org.Lwes / Event.cs
blob8f1169bb1700f8e396050826d8b43113f8c08c30
1 namespace Org.Lwes
3 using System;
4 using System.Net;
5 using System.Text;
7 using Org.Lwes.DB;
8 using Org.Lwes.ESF;
9 using Org.Lwes.Properties;
11 /// <summary>
12 /// Event base class.
13 /// </summary>
14 [Serializable]
15 public struct Event
17 #region Fields
19 IEventAttribute[] _attributes;
20 SupportedEncoding _encoding;
21 EventTemplate _template;
22 bool _validating;
24 #endregion Fields
26 #region Constructors
28 /// <summary>
29 /// Creates a new event with the given name.
30 /// </summary>
31 public Event(string evName)
32 : this(new EventTemplate(false, evName), false, Constants.CDefaultSupportedEncoding)
36 /// <summary>
37 /// Creates a new instance with an encoding.
38 /// </summary>
39 /// <param name="enc">An encoding for the event.</param>
40 public Event(SupportedEncoding enc)
41 : this(EventTemplate.Empty, false, enc)
45 /// <summary>
46 /// Creates a new event.
47 /// </summary>
48 /// <param name="evTemplate">the event's template</param>
49 /// <param name="validating"><em>true</em> if validating should be performed on the event;
50 /// otherwise <em>false</em></param>
51 /// <param name="enc">indicates the encoding to use for the event's character data</param>
52 public Event(EventTemplate evTemplate, bool validating, SupportedEncoding enc)
54 _template = evTemplate;
55 _validating = validating;
56 _encoding = enc;
57 _attributes = new IEventAttribute[evTemplate.Count];
60 /// <summary>
61 /// Constructor used by mutators.
62 /// </summary>
63 private Event(EventTemplate t, bool validating, SupportedEncoding enc
64 , IEventAttribute[] attributes)
66 _template = t;
67 _validating = validating;
68 _encoding = enc;
69 _attributes = attributes;
72 #endregion Constructors
74 #region Properties
76 /// <summary>
77 /// Gets the attribute count.
78 /// </summary>
79 public int AttributeCount
81 get { return _template.Count; }
84 /// <summary>
85 /// Gets the encoding used when the event is encoded for binary transmission.
86 /// </summary>
87 public SupportedEncoding Encoding
89 get { return _encoding; }
92 /// <summary>
93 /// The event's name.
94 /// </summary>
95 public string Name
97 get { return _template.Name; }
100 #endregion Properties
102 #region Indexers
104 /// <summary>
105 /// Gets an attribute by name.
106 /// </summary>
107 /// <param name="name">attribute name</param>
108 /// <returns>the attribute if it exists; otherwise an exception is thrown</returns>
109 /// <exception cref="ArgumentOutOfRangeException">thrown if an attribute with the given <paramref name="name"/> doesn't exist</exception>
110 public IEventAttribute this[string name]
114 int ord;
115 if (!_template.TryGetOrdinal(name, out ord))
116 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
117 return _attributes[ord];
121 /// <summary>
122 /// Gets an attribute by ordinal position.
123 /// </summary>
124 /// <param name="ord">ordinal position of the attribute</param>
125 /// <returns>an attribute at the <paramref name="ordinal"/> position given</returns>
126 /// <exception cref="ArgumentOutOfRangeException">thrown if the <paramref name="ordinal"/> is out of range</exception>
127 public IEventAttribute this[int ord]
131 if (0 > ord || ord >= _attributes.Length)
132 throw new ArgumentOutOfRangeException("ordinal");
133 return _attributes[ord];
137 #endregion Indexers
139 #region Methods
141 /// <summary>
142 /// Gets an attribute's value.
143 /// </summary>
144 /// <typeparam name="V">value type V</typeparam>
145 /// <param name="name">attribute's name.</param>
146 /// <returns>The value of the attribute, as type V</returns>
147 /// <exception cref="InvalidCastException">if the attribute's value cannot be
148 /// coerced into value type V</exception>
149 /// <exception cref="NoSuchAttributeException">thrown if an attribute with the given name
150 /// does not exist.</exception>
151 public V GetValue<V>(string name)
153 int ord;
154 if (_template.TryGetOrdinal(name, out ord))
156 return _attributes[ord].GetValue<V>();
158 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
161 /// <summary>
162 /// Sets an attribute's value.
163 /// </summary>
164 /// <param name="name">the attribute's name</param>
165 /// <param name="value">the attribute's UInt16 value</param>
166 public Event SetValue(string name, UInt16 value)
168 int ord;
169 AttributeTemplate attr;
170 if (_template.TryGetOrdinal(name, out ord))
172 attr = _template[ord];
174 // Validate if necessary
175 if (_validating && !attr.IsAssignable(value))
176 throw new AttributeNotSetException("name");
178 return Mutate(ord, _attributes[ord].Mutate(_template, value));
181 if (_validating)
183 // Allow for SiteID or SenderPort inherited from MetaInfoEvent
184 if (!String.Equals(Constants.MetaEventInfoAttributes.SiteID.Name, name)
185 && !String.Equals(Constants.MetaEventInfoAttributes.SenderPort.Name, name))
186 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
189 // Adding a new attribute
190 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
193 /// <summary>
194 /// Sets an attribute's value.
195 /// </summary>
196 /// <param name="name">the attribute's name</param>
197 /// <param name="value">the attribute's Int16 value</param>
198 public Event SetValue(string name, Int16 value)
200 int ord;
201 AttributeTemplate attr;
202 if (_template.TryGetOrdinal(name, out ord))
204 attr = _template[ord];
206 // Validate if necessary
207 if (_validating && !attr.IsAssignable(value))
208 throw new AttributeNotSetException("name");
210 return Mutate(ord, _attributes[ord].Mutate(_template, value));
213 // Allow for Encoding inherited from MetaInfoEvent
214 if (String.Equals(Constants.MetaEventInfoAttributes.Encoding.Name, name))
216 // encoding must be the first attribute (when encoded), make it so
217 return PrependAttribute(Constants.MetaEventInfoAttributes.Encoding, value);
220 if (_validating)
221 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
223 // Adding a new attribute
224 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
227 /// <summary>
228 /// Sets an attribute's value.
229 /// </summary>
230 /// <param name="name">the attribute's name</param>
231 /// <param name="value">the attribute's UInt32 value</param>
232 public Event SetValue(string name, UInt32 value)
234 int ord;
235 AttributeTemplate attr;
236 if (_template.TryGetOrdinal(name, out ord))
238 attr = _template[ord];
240 // Validate if necessary
241 if (_validating && !attr.IsAssignable(value))
242 throw new AttributeNotSetException("name");
244 return Mutate(ord, _attributes[ord].Mutate(_template, value));
247 if (_validating)
248 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
250 // Adding a new attribute
251 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
254 /// <summary>
255 /// Sets an attribute's value.
256 /// </summary>
257 /// <param name="name">the attribute's name</param>
258 /// <param name="value">the attribute's Int32 value</param>
259 public Event SetValue(string name, Int32 value)
261 int ord;
262 AttributeTemplate attr;
263 if (_template.TryGetOrdinal(name, out ord))
265 attr = _template[ord];
267 // Validate if necessary
268 if (_validating && !attr.IsAssignable(value))
269 throw new AttributeNotSetException("name");
271 return Mutate(ord, _attributes[ord].Mutate(_template, value));
274 if (_validating)
275 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
277 // Adding a new attribute
278 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
281 /// <summary>
282 /// Sets an attribute's value.
283 /// </summary>
284 /// <param name="name">the attribute's name</param>
285 /// <param name="value">the attribute's String value</param>
286 public Event SetValue(string name, String value)
288 int ord;
289 AttributeTemplate attr;
290 if (_template.TryGetOrdinal(name, out ord))
292 attr = _template[ord];
294 // Validate if necessary
295 if (_validating && !attr.IsAssignable(value))
296 throw new AttributeNotSetException("name");
298 return Mutate(ord, _attributes[ord].Mutate(_template, value));
301 if (_validating)
302 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
304 // Adding a new attribute
305 return AppendAttribute( AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
308 /// <summary>
309 /// Sets an attribute's value.
310 /// </summary>
311 /// <param name="name">the attribute's name</param>
312 /// <param name="value">the attribute's IPAddress value</param>
313 public Event SetValue(string name, IPAddress value)
315 int ord;
316 AttributeTemplate attr;
317 if (_template.TryGetOrdinal(name, out ord))
319 attr = _template[ord];
321 // Validate if necessary
322 if (_validating && !attr.IsAssignable(value))
323 throw new AttributeNotSetException("name");
325 return Mutate(ord, _attributes[ord].Mutate(_template, value));
328 if (_validating)
330 // Allow for SenderIP inherited from MetaInfoEvent
331 if (!String.Equals(Constants.MetaEventInfoAttributes.SenderIP.Name, name))
332 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
335 // Adding a new attribute
336 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
339 /// <summary>
340 /// Sets an attribute's value.
341 /// </summary>
342 /// <param name="name">the attribute's name</param>
343 /// <param name="value">the attribute's Int64 value</param>
344 public Event SetValue(string name, Int64 value)
346 int ord;
347 AttributeTemplate attr;
348 if (_template.TryGetOrdinal(name, out ord))
350 attr = _template[ord];
352 // Validate if necessary
353 if (_validating && !attr.IsAssignable(value))
354 throw new AttributeNotSetException("name");
356 return Mutate(ord, _attributes[ord].Mutate(_template, value));
359 if (_validating)
361 // Allow for ReceiptTime inherited from MetaInfoEvent
362 if (!String.Equals(Constants.MetaEventInfoAttributes.ReceiptTime.Name, name))
363 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
366 // Adding a new attribute
367 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
370 /// <summary>
371 /// Sets an attribute's value.
372 /// </summary>
373 /// <param name="name">the attribute's name</param>
374 /// <param name="value">the attribute's UInt64 value</param>
375 public Event SetValue(string name, UInt64 value)
377 int ord;
378 AttributeTemplate attr;
379 if (_template.TryGetOrdinal(name, out ord))
381 attr = _template[ord];
383 // Validate if necessary
384 if (_validating && !attr.IsAssignable(value))
385 throw new AttributeNotSetException("name");
387 return Mutate(ord, _attributes[ord].Mutate(_template, value));
390 if (_validating)
391 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
393 // Adding a new attribute
394 return AppendAttribute(AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
397 /// <summary>
398 /// Sets an attribute's value.
399 /// </summary>
400 /// <param name="name">the attribute's name</param>
401 /// <param name="value">the attribute's Boolean value</param>
402 public Event SetValue(string name, Boolean value)
404 int ord;
405 AttributeTemplate attr;
406 if (_template.TryGetOrdinal(name, out ord))
408 attr = _template[ord];
410 // Validate if necessary
411 if (_validating && !attr.IsAssignable(value))
412 throw new AttributeNotSetException("name");
414 return Mutate(ord, _attributes[ord].Mutate(_template, value));
417 if (_validating)
418 throw new ArgumentOutOfRangeException("name", String.Format(Resources.Error_AttributeNotDefined, name));
420 // Adding a new attribute
421 return AppendAttribute( AttributeTemplate.CreateTemplateForVariable(name, 0, value), value);
424 /// <summary>
425 /// Converts the event to a string.
426 /// </summary>
427 /// <returns>String containing the event.</returns>
428 public override string ToString()
430 StringBuilder s = new StringBuilder(400);
431 s.Append(_template.Name).Append(": { Name: '").Append(_template.Name)
432 .Append("', FromESF: ").Append(_template.FromEsf)
433 .Append(", Attributes: {");
434 if (_attributes != null)
436 int i = 0;
437 foreach (var a in _attributes)
439 if (i++ > 0) s.Append(", ").Append(a);
440 else s.Append(a);
443 return s.Append("}}").ToString();
446 /// <summary>
447 /// Converts the event to a string.
448 /// </summary>
449 /// <param name="humanReadable">Whether the output should be formatted for human readability</param>
450 /// <returns>string contianing the event</returns>
451 public string ToString(bool humanReadable)
453 if (!humanReadable) return ToString();
455 string nl = Environment.NewLine;
457 StringBuilder s = new StringBuilder(400);
458 s.Append(_template.Name).Append(":").Append(nl).Append(" { Name: '").Append(_template.Name)
459 .Append("'").Append(nl).Append(" , FromESF: ").Append(_template.FromEsf)
460 .Append(nl).Append(" , Attributes: {");
461 if (_attributes != null)
463 int i = 0;
464 foreach (var a in _attributes)
466 if (i++ > 0) s.Append(nl).Append(" , ").Append(a);
467 else s.Append(a);
470 return s.Append(nl).Append(" }").Append(nl).Append(" }").ToString();
473 /// <summary>
474 /// Tries to get an attribute.
475 /// </summary>
476 /// <param name="name">attribute's name</param>
477 /// <param name="value">reference to a variable where the attribute will be stored upon success</param>
478 /// <returns><em>true</em> if the attribute exists; otherwise <em>false</em></returns>
479 public bool TryGetAttribute(string name, out IEventAttribute value)
481 int ord;
482 if (_template.TryGetOrdinal(name, out ord))
484 value = _attributes[ord];
485 return true;
487 value = default(IEventAttribute);
488 return false;
491 /// <summary>
492 /// Tries to get an attribute's value as a UInt16.
493 /// </summary>
494 /// <param name="attr">the attribute's name</param>
495 /// <param name="value">reference to a variable to hold the value</param>
496 /// <returns><em>true</em> if the value can be retrieved as a UInt16, otherwise <em>false</em></returns>
497 public bool TryGetValue(string attr, out ushort value)
499 int ord;
500 if (_template.TryGetOrdinal(attr, out ord))
502 return _attributes[ord].TryGetValue(out value);
504 value = default(ushort);
505 return false;
508 /// <summary>
509 /// Tries to get an attribute's value as a Int16.
510 /// </summary>
511 /// <param name="attr">the attribute's name</param>
512 /// <param name="value">reference to a variable to hold the value</param>
513 /// <returns><em>true</em> if the value can be retrieved as a Int16, otherwise <em>false</em></returns>
514 public bool TryGetValue(string attr, out short value)
516 int ord;
517 if (_template.TryGetOrdinal(attr, out ord))
519 return _attributes[ord].TryGetValue(out value);
521 value = default(short);
522 return false;
525 /// <summary>
526 /// Tries to get an attribute's value as a UInt32.
527 /// </summary>
528 /// <param name="attr">the attribute's name</param>
529 /// <param name="value">reference to a variable to hold the value</param>
530 /// <returns><em>true</em> if the value can be retrieved as a UInt32, otherwise <em>false</em></returns>
531 public bool TryGetValue(string attr, out uint value)
533 int ord;
534 if (_template.TryGetOrdinal(attr, out ord))
536 return _attributes[ord].TryGetValue(out value);
538 value = default(uint);
539 return false;
542 /// <summary>
543 /// Tries to get an attribute's value as a Int32.
544 /// </summary>
545 /// <param name="attr">the attribute's name</param>
546 /// <param name="value">reference to a variable to hold the value</param>
547 /// <returns><em>true</em> if the value can be retrieved as a Int32, otherwise <em>false</em></returns>
548 public bool TryGetValue(string attr, out int value)
550 int ord;
551 if (_template.TryGetOrdinal(attr, out ord))
553 return _attributes[ord].TryGetValue(out value);
555 value = default(int);
556 return false;
559 /// <summary>
560 /// Tries to get an attribute's value as a string.
561 /// </summary>
562 /// <param name="attr">the attribute's name</param>
563 /// <param name="value">reference to a variable to hold the value</param>
564 /// <returns><em>true</em> if the value can be retrieved as a string, otherwise <em>false</em></returns>
565 public bool TryGetValue(string attr, out string value)
567 int ord;
568 if (_template.TryGetOrdinal(attr, out ord))
570 return _attributes[ord].TryGetValue(out value);
572 value = default(string);
573 return false;
576 /// <summary>
577 /// Tries to get an attribute's value as a IPAddress.
578 /// </summary>
579 /// <param name="attr">the attribute's name</param>
580 /// <param name="value">reference to a variable to hold the value</param>
581 /// <returns><em>true</em> if the value can be retrieved as a IPAddress, otherwise <em>false</em></returns>
582 public bool TryGetValue(string attr, out IPAddress value)
584 int ord;
585 if (_template.TryGetOrdinal(attr, out ord))
587 return _attributes[ord].TryGetValue(out value);
589 value = default(IPAddress);
590 return false;
593 /// <summary>
594 /// Tries to get an attribute's value as a UInt16.
595 /// </summary>
596 /// <param name="attr">the attribute's name</param>
597 /// <param name="value">reference to a variable to hold the value</param>
598 /// <returns><em>true</em> if the value can be retrieved as a UInt16, otherwise <em>false</em></returns>
599 public bool TryGetValue(string attr, out long value)
601 int ord;
602 if (_template.TryGetOrdinal(attr, out ord))
604 return _attributes[ord].TryGetValue(out value);
606 value = default(long);
607 return false;
610 /// <summary>
611 /// Tries to get an attribute's value as a UInt64.
612 /// </summary>
613 /// <param name="attr">the attribute's name</param>
614 /// <param name="value">reference to a variable to hold the value</param>
615 /// <returns><em>true</em> if the value can be retrieved as a UInt64, otherwise <em>false</em></returns>
616 public bool TryGetValue(string attr, out ulong value)
618 int ord;
619 if (_template.TryGetOrdinal(attr, out ord))
621 return _attributes[ord].TryGetValue(out value);
623 value = default(ulong);
624 return false;
627 /// <summary>
628 /// Tries to get an attribute's value as a Boolean.
629 /// </summary>
630 /// <param name="attr">the attribute's name</param>
631 /// <param name="value">reference to a variable to hold the value</param>
632 /// <returns><em>true</em> if the value can be retrieved as a Boolean, otherwise <em>false</em></returns>
633 public bool TryGetValue(string attr, out bool value)
635 int ord;
636 if (_template.TryGetOrdinal(attr, out ord))
638 return _attributes[ord].TryGetValue(out value);
640 value = default(bool);
641 return false;
644 internal static Event BinaryDecode(IEventTemplateDB db, byte[] buffer, int offset, int count)
646 Decoder dec = Constants.DefaultEncoding.GetDecoder();
647 Decoder bodyDecoder = dec;
648 int ofs = offset, end_of_input = offset + count;
650 string eventName = LwesSerializer.ReadEVENTWORD(buffer, ref ofs, dec);
651 UInt16 attributeCount = LwesSerializer.ReadUInt16(buffer, ref ofs);
653 Event ev;
654 if (!db.TryCreateEvent(eventName, out ev, false, SupportedEncoding.Default))
656 ev = new Event(new EventTemplate(false, eventName), false, SupportedEncoding.Default);
659 for (int i = 0; i < attributeCount && ofs < end_of_input; i++)
661 string attributeName = LwesSerializer.ReadATTRIBUTEWORD(buffer, ref ofs, dec);
662 TypeToken attributeTokenType = (TypeToken)LwesSerializer.ReadByte(buffer, ref ofs);
664 // Encoding is in the first attribute position if it is present
665 if (i == 0
666 && String.Equals(Constants.MetaEventInfoAttributes.Encoding, attributeName)
667 && attributeTokenType == TypeToken.UINT16)
669 Int16 changeEncoding = LwesSerializer.ReadInt16(buffer, ref ofs);
670 bodyDecoder = Constants.GetEncoding(changeEncoding).GetDecoder();
671 ev = ev.SetValue(Constants.MetaEventInfoAttributes.Encoding.Name, changeEncoding);
673 else
675 switch (attributeTokenType)
677 case TypeToken.UINT16:
678 ev = ev.SetValue(attributeName, LwesSerializer.ReadUInt16(buffer, ref ofs));
679 break;
680 case TypeToken.INT16:
681 ev = ev.SetValue(attributeName, LwesSerializer.ReadInt16(buffer, ref ofs));
682 break;
683 case TypeToken.UINT32:
684 ev = ev.SetValue(attributeName, LwesSerializer.ReadUInt32(buffer, ref ofs));
685 break;
686 case TypeToken.INT32:
687 ev = ev.SetValue(attributeName, LwesSerializer.ReadInt32(buffer, ref ofs));
688 break;
689 case TypeToken.STRING:
690 ev = ev.SetValue(attributeName, LwesSerializer.ReadString(buffer, ref ofs, bodyDecoder));
691 break;
692 case TypeToken.IP_ADDR:
693 ev = ev.SetValue(attributeName, LwesSerializer.ReadIPAddress(buffer, ref ofs));
694 break;
695 case TypeToken.INT64:
696 ev = ev.SetValue(attributeName, LwesSerializer.ReadInt64(buffer, ref ofs));
697 break;
698 case TypeToken.UINT64:
699 ev = ev.SetValue(attributeName, LwesSerializer.ReadUInt64(buffer, ref ofs));
700 break;
701 case TypeToken.BOOLEAN:
702 ev = ev.SetValue(attributeName, LwesSerializer.ReadBoolean(buffer, ref ofs));
703 break;
708 return ev;
711 internal int BinaryEncode(byte[] buffer, int offset)
713 /* Encoded using the following protocol:
715 * EVENTWORD,<number of elements>,ATTRIBUTEWORD,TYPETOKEN,
716 * (UINT16|INT16|UINT32|INT32|UINT64|INT64|BOOLEAN|STRING)
717 * ...ATTRIBUTEWORD,TYPETOKEN(UINT16|INT16|UINT32|INT32|
718 * UINT64|INT64|BOOLEAN|STRING)
720 * The EVENTWORD and ATTRIBUTEWORD(s) are encoded with
721 * the default encoding, the first attribute will be the
722 * encoding for strings if present (may differ from the
723 * encoding used for EVENTWORD and ATTRIBUTEWORD(s)
726 int count = 0, ofs = offset;
727 Encoder utf8 = Constants.DefaultEncoding.GetEncoder();
728 Encoder bodyEncoder = Constants.GetEncoding((short)_encoding).GetEncoder();
730 // Encode the EVENTWORD + attribute-count
731 _template.BinaryEncode(buffer, ref ofs);
733 // All of the template and dynamic attributes are encoded...
734 for (int i = 0; i < _attributes.Length; i++)
736 count += _attributes[i].BinaryEncode(buffer, ref ofs, bodyEncoder);
739 offset = ofs;
740 return count;
743 internal int CalculateEncodedByteCount()
745 Encoding enc = Constants.GetEncoding((short)_encoding);
746 int count = _template.GetByteCount();
748 // All of the template and dynamic attributes are encoded...
749 for(int i = 0; i < _attributes.Length; i++)
751 count += _attributes[i].GetByteCount(enc);
753 return count;
756 private Event AppendAttribute<T>(AttributeTemplate attr, T value)
758 EventTemplate et = _template.AppendAttributes(attr);
759 IEventAttribute[] attributes = new IEventAttribute[_attributes.Length + 1];
760 Array.Copy(_attributes, attributes, _attributes.Length);
761 attributes[attributes.Length - 1] = new EventAttribute<T>(attr, value);
762 return new Event(et, _validating, _encoding, attributes);
765 private Event Mutate(int ord, IEventAttribute attr)
767 IEventAttribute[] copy = (IEventAttribute[])_attributes.Clone();
768 copy[ord] = attr;
769 return new Event(_template, _validating, _encoding, copy);
772 private Event PrependAttribute<T>(AttributeTemplate attr, T value)
774 EventTemplate et = _template.PrependAttributes(attr);
775 IEventAttribute[] attributes = new IEventAttribute[_attributes.Length + 1];
776 Array.Copy(_attributes, 0, attributes, 1, _attributes.Length);
777 attributes[0] = new EventAttribute<T>(attr, value);
778 return new Event(et, _validating, _encoding, attributes);
781 #endregion Methods