892 lines
28 KiB
C#
892 lines
28 KiB
C#
|
//------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//------------------------------------------------------------
|
||
|
|
||
|
namespace System.ServiceModel.Channels
|
||
|
{
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Runtime;
|
||
|
using System.ServiceModel.Security;
|
||
|
|
||
|
public sealed class MessageProperties : IDictionary<string, object>, IDisposable
|
||
|
{
|
||
|
Property[] properties;
|
||
|
int propertyCount;
|
||
|
MessageEncoder encoder;
|
||
|
Uri via;
|
||
|
object allowOutputBatching;
|
||
|
SecurityMessageProperty security;
|
||
|
bool disposed;
|
||
|
const int InitialPropertyCount = 2;
|
||
|
const int MaxRecycledArrayLength = 8;
|
||
|
const string ViaKey = "Via";
|
||
|
const string AllowOutputBatchingKey = "AllowOutputBatching";
|
||
|
const string SecurityKey = "Security";
|
||
|
const string EncoderKey = "Encoder";
|
||
|
const int NotFoundIndex = -1;
|
||
|
const int ViaIndex = -2;
|
||
|
const int AllowOutputBatchingIndex = -3;
|
||
|
const int SecurityIndex = -4;
|
||
|
const int EncoderIndex = -5;
|
||
|
static object trueBool = true;
|
||
|
static object falseBool = false;
|
||
|
|
||
|
public MessageProperties()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public MessageProperties(MessageProperties properties)
|
||
|
{
|
||
|
CopyProperties(properties);
|
||
|
}
|
||
|
|
||
|
internal MessageProperties(KeyValuePair<string, object>[] array)
|
||
|
{
|
||
|
if (array == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array"));
|
||
|
CopyProperties(array);
|
||
|
}
|
||
|
|
||
|
void ThrowDisposed()
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(string.Empty, SR.GetString(SR.ObjectDisposed, this.GetType().ToString())));
|
||
|
}
|
||
|
|
||
|
public object this[string name]
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
object value;
|
||
|
|
||
|
if (!TryGetValue(name, out value))
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertyNotFound, name)));
|
||
|
}
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
UpdateProperty(name, value, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool CanRecycle
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return properties == null || properties.Length <= MaxRecycledArrayLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int Count
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return propertyCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public MessageEncoder Encoder
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return encoder;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
AdjustPropertyCount((object)encoder == null, (object)value == null);
|
||
|
encoder = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool AllowOutputBatching
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return (object)allowOutputBatching == trueBool;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
AdjustPropertyCount((object)allowOutputBatching == null, false);
|
||
|
|
||
|
if (value)
|
||
|
{
|
||
|
allowOutputBatching = trueBool;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
allowOutputBatching = falseBool;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsFixedSize
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsReadOnly
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ICollection<string> Keys
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
List<string> keys = new List<string>();
|
||
|
|
||
|
if ((object)via != null)
|
||
|
{
|
||
|
keys.Add(ViaKey);
|
||
|
}
|
||
|
|
||
|
if ((object)allowOutputBatching != null)
|
||
|
{
|
||
|
keys.Add(AllowOutputBatchingKey);
|
||
|
}
|
||
|
|
||
|
if ((object)security != null)
|
||
|
{
|
||
|
keys.Add(SecurityKey);
|
||
|
}
|
||
|
|
||
|
if ((object)encoder != null)
|
||
|
{
|
||
|
keys.Add(EncoderKey);
|
||
|
}
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
string propertyName = properties[i].Name;
|
||
|
|
||
|
if (propertyName == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
keys.Add(propertyName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return keys;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public SecurityMessageProperty Security
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return security;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
AdjustPropertyCount((object)security == null, (object)value == null);
|
||
|
security = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ICollection<object> Values
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
List<object> values = new List<object>();
|
||
|
|
||
|
if ((object)via != null)
|
||
|
{
|
||
|
values.Add(via);
|
||
|
}
|
||
|
|
||
|
if ((object)allowOutputBatching != null)
|
||
|
{
|
||
|
values.Add(allowOutputBatching);
|
||
|
}
|
||
|
|
||
|
if ((object)security != null)
|
||
|
{
|
||
|
values.Add(security);
|
||
|
}
|
||
|
|
||
|
if ((object)encoder != null)
|
||
|
{
|
||
|
values.Add(encoder);
|
||
|
}
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
if (properties[i].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
values.Add(properties[i].Value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return values;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Uri Via
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
return via;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
AdjustPropertyCount((object)via == null, (object)value == null);
|
||
|
via = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Add(string name, object property)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (property == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("property"));
|
||
|
UpdateProperty(name, property, true);
|
||
|
}
|
||
|
|
||
|
void AdjustPropertyCount(bool oldValueIsNull, bool newValueIsNull)
|
||
|
{
|
||
|
if (newValueIsNull)
|
||
|
{
|
||
|
if (!oldValueIsNull)
|
||
|
{
|
||
|
propertyCount--;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (oldValueIsNull)
|
||
|
{
|
||
|
propertyCount++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Clear()
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
if (properties[i].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
properties[i] = new Property();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
via = null;
|
||
|
allowOutputBatching = null;
|
||
|
security = null;
|
||
|
encoder = null;
|
||
|
propertyCount = 0;
|
||
|
}
|
||
|
|
||
|
public void CopyProperties(MessageProperties properties)
|
||
|
{
|
||
|
// CopyProperties behavior should be equivalent to the behavior
|
||
|
// of MergeProperties except that Merge supports property values that
|
||
|
// implement the IMergeEnabledMessageProperty. Any changes to CopyProperties
|
||
|
// should be reflected in MergeProperties as well.
|
||
|
if (properties == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
|
||
|
}
|
||
|
|
||
|
if (disposed)
|
||
|
{
|
||
|
ThrowDisposed();
|
||
|
}
|
||
|
|
||
|
if (properties.properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.properties.Length; i++)
|
||
|
{
|
||
|
if (properties.properties[i].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Property property = properties.properties[i];
|
||
|
|
||
|
// this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
|
||
|
this[property.Name] = property.Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.Via = properties.Via;
|
||
|
this.AllowOutputBatching = properties.AllowOutputBatching;
|
||
|
this.Security = (properties.Security != null) ? (SecurityMessageProperty)properties.Security.CreateCopy() : null;
|
||
|
this.Encoder = properties.Encoder;
|
||
|
}
|
||
|
|
||
|
internal void MergeProperties(MessageProperties properties)
|
||
|
{
|
||
|
// MergeProperties behavior should be equivalent to the behavior
|
||
|
// of CopyProperties except that Merge supports property values that
|
||
|
// implement the IMergeEnabledMessageProperty. Any changes to CopyProperties
|
||
|
// should be reflected in MergeProperties as well.
|
||
|
if (properties == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
|
||
|
}
|
||
|
|
||
|
if (disposed)
|
||
|
{
|
||
|
ThrowDisposed();
|
||
|
}
|
||
|
|
||
|
if (properties.properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.properties.Length; i++)
|
||
|
{
|
||
|
if (properties.properties[i].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Property property = properties.properties[i];
|
||
|
|
||
|
IMergeEnabledMessageProperty currentValue;
|
||
|
if (!this.TryGetValue<IMergeEnabledMessageProperty>(property.Name, out currentValue) ||
|
||
|
!currentValue.TryMergeWithProperty(property.Value))
|
||
|
{
|
||
|
// Merge wasn't possible so copy
|
||
|
// this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
|
||
|
this[property.Name] = property.Value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.Via = properties.Via;
|
||
|
this.AllowOutputBatching = properties.AllowOutputBatching;
|
||
|
this.Security = (properties.Security != null) ? (SecurityMessageProperty)properties.Security.CreateCopy() : null;
|
||
|
this.Encoder = properties.Encoder;
|
||
|
}
|
||
|
|
||
|
internal void CopyProperties(KeyValuePair<string, object>[] array)
|
||
|
{
|
||
|
if (disposed)
|
||
|
{
|
||
|
ThrowDisposed();
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < array.Length; i++)
|
||
|
{
|
||
|
KeyValuePair<string, object> property = array[i];
|
||
|
|
||
|
// this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
|
||
|
this[property.Key] = property.Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool ContainsKey(string name)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (name == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
|
||
|
int index = FindProperty(name);
|
||
|
switch (index)
|
||
|
{
|
||
|
case ViaIndex:
|
||
|
return (object)via != null;
|
||
|
case AllowOutputBatchingIndex:
|
||
|
return (object)allowOutputBatching != null;
|
||
|
case SecurityIndex:
|
||
|
return (object)security != null;
|
||
|
case EncoderIndex:
|
||
|
return (object)encoder != null;
|
||
|
case NotFoundIndex:
|
||
|
return false;
|
||
|
default:
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
object CreateCopyOfPropertyValue(object propertyValue)
|
||
|
{
|
||
|
IMessageProperty messageProperty = propertyValue as IMessageProperty;
|
||
|
if (messageProperty == null)
|
||
|
return propertyValue;
|
||
|
object copy = messageProperty.CreateCopy();
|
||
|
if (copy == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertyReturnedNullCopy)));
|
||
|
return copy;
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (disposed)
|
||
|
return;
|
||
|
|
||
|
disposed = true;
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
if (properties[i].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
properties[i].Dispose();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.security != null)
|
||
|
{
|
||
|
this.security.Dispose();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int FindProperty(string name)
|
||
|
{
|
||
|
if (name == ViaKey)
|
||
|
return ViaIndex;
|
||
|
else if (name == AllowOutputBatchingKey)
|
||
|
return AllowOutputBatchingIndex;
|
||
|
else if (name == EncoderKey)
|
||
|
return EncoderIndex;
|
||
|
else if (name == SecurityKey)
|
||
|
return SecurityIndex;
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
string propertyName = properties[i].Name;
|
||
|
|
||
|
if (propertyName == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (propertyName == name)
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NotFoundIndex;
|
||
|
}
|
||
|
|
||
|
internal void Recycle()
|
||
|
{
|
||
|
disposed = false;
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
public bool Remove(string name)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
int originalPropertyCount = propertyCount;
|
||
|
UpdateProperty(name, null, false);
|
||
|
return originalPropertyCount != propertyCount;
|
||
|
}
|
||
|
|
||
|
public bool TryGetValue(string name, out object value)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (name == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
|
||
|
|
||
|
int index = FindProperty(name);
|
||
|
switch (index)
|
||
|
{
|
||
|
case ViaIndex:
|
||
|
value = via;
|
||
|
break;
|
||
|
case AllowOutputBatchingIndex:
|
||
|
value = allowOutputBatching;
|
||
|
break;
|
||
|
case SecurityIndex:
|
||
|
value = security;
|
||
|
break;
|
||
|
case EncoderIndex:
|
||
|
value = encoder;
|
||
|
break;
|
||
|
case NotFoundIndex:
|
||
|
value = null;
|
||
|
break;
|
||
|
default:
|
||
|
value = properties[index].Value;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return value != null;
|
||
|
}
|
||
|
|
||
|
internal bool TryGetValue<TProperty>(string name, out TProperty property)
|
||
|
{
|
||
|
object o;
|
||
|
if (this.TryGetValue(name, out o))
|
||
|
{
|
||
|
property = (TProperty)o;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
property = default(TProperty);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal TProperty GetValue<TProperty>(string name) where TProperty : class
|
||
|
{
|
||
|
return this.GetValue<TProperty>(name, false);
|
||
|
}
|
||
|
|
||
|
internal TProperty GetValue<TProperty>(string name, bool ensureTypeMatch) where TProperty : class
|
||
|
{
|
||
|
object obj;
|
||
|
if (!this.TryGetValue(name, out obj))
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return ensureTypeMatch ? (TProperty)obj : obj as TProperty;
|
||
|
}
|
||
|
|
||
|
void UpdateProperty(string name, object value, bool mustNotExist)
|
||
|
{
|
||
|
if (name == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
|
||
|
int index = FindProperty(name);
|
||
|
if (index != NotFoundIndex)
|
||
|
{
|
||
|
if (mustNotExist)
|
||
|
{
|
||
|
bool exists;
|
||
|
switch (index)
|
||
|
{
|
||
|
case ViaIndex:
|
||
|
exists = (object)via != null;
|
||
|
break;
|
||
|
case AllowOutputBatchingIndex:
|
||
|
exists = (object)allowOutputBatching != null;
|
||
|
break;
|
||
|
case SecurityIndex:
|
||
|
exists = (object)security != null;
|
||
|
break;
|
||
|
case EncoderIndex:
|
||
|
exists = (object)encoder != null;
|
||
|
break;
|
||
|
default:
|
||
|
exists = true;
|
||
|
break;
|
||
|
}
|
||
|
if (exists)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.DuplicateMessageProperty, name)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (index >= 0)
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
properties[index].Dispose();
|
||
|
int shiftIndex;
|
||
|
for (shiftIndex = index + 1; shiftIndex < properties.Length; shiftIndex++)
|
||
|
{
|
||
|
if (properties[shiftIndex].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
properties[shiftIndex - 1] = properties[shiftIndex];
|
||
|
}
|
||
|
properties[shiftIndex - 1] = new Property();
|
||
|
propertyCount--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
properties[index].Value = CreateCopyOfPropertyValue(value);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (index)
|
||
|
{
|
||
|
case ViaIndex:
|
||
|
Via = (Uri)value;
|
||
|
break;
|
||
|
case AllowOutputBatchingIndex:
|
||
|
AllowOutputBatching = (bool)value;
|
||
|
break;
|
||
|
case SecurityIndex:
|
||
|
if (Security != null)
|
||
|
Security.Dispose();
|
||
|
Security = (SecurityMessageProperty)CreateCopyOfPropertyValue(value);
|
||
|
break;
|
||
|
case EncoderIndex:
|
||
|
Encoder = (MessageEncoder)value;
|
||
|
break;
|
||
|
default:
|
||
|
Fx.Assert("");
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (value != null)
|
||
|
{
|
||
|
int newIndex;
|
||
|
|
||
|
if (properties == null)
|
||
|
{
|
||
|
properties = new Property[InitialPropertyCount];
|
||
|
newIndex = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (newIndex = 0; newIndex < properties.Length; newIndex++)
|
||
|
{
|
||
|
if (properties[newIndex].Name == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (newIndex == properties.Length)
|
||
|
{
|
||
|
Property[] newProperties = new Property[properties.Length * 2];
|
||
|
Array.Copy(properties, newProperties, properties.Length);
|
||
|
properties = newProperties;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
object newValue = CreateCopyOfPropertyValue(value);
|
||
|
properties[newIndex] = new Property(name, newValue);
|
||
|
propertyCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int index)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (array == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array"));
|
||
|
if (array.Length < propertyCount)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertiesArraySize0)));
|
||
|
if (index < 0 || index > array.Length - propertyCount)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index", index,
|
||
|
SR.GetString(SR.ValueMustBeInRange, 0, array.Length - propertyCount)));
|
||
|
|
||
|
if (this.via != null)
|
||
|
array[index++] = new KeyValuePair<string, object>(ViaKey, via);
|
||
|
|
||
|
if (this.allowOutputBatching != null)
|
||
|
array[index++] = new KeyValuePair<string, object>(AllowOutputBatchingKey, allowOutputBatching);
|
||
|
|
||
|
if (this.security != null)
|
||
|
array[index++] = new KeyValuePair<string, object>(SecurityKey, this.security.CreateCopy());
|
||
|
|
||
|
if (this.encoder != null)
|
||
|
array[index++] = new KeyValuePair<string, object>(EncoderKey, encoder);
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
string propertyName = properties[i].Name;
|
||
|
|
||
|
if (propertyName == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
array[index++] = new KeyValuePair<string, object>(propertyName, CreateCopyOfPropertyValue(properties[i].Value));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> pair)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (pair.Value == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
|
||
|
UpdateProperty(pair.Key, pair.Value, true);
|
||
|
}
|
||
|
|
||
|
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> pair)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (pair.Value == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
|
||
|
if (pair.Key == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Key"));
|
||
|
object value;
|
||
|
if (!TryGetValue(pair.Key, out value))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return value.Equals(pair.Value);
|
||
|
}
|
||
|
|
||
|
IEnumerator IEnumerable.GetEnumerator()
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
return ((IEnumerable<KeyValuePair<string, object>>)this).GetEnumerator();
|
||
|
}
|
||
|
|
||
|
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
List<KeyValuePair<string, object>> pairs = new List<KeyValuePair<string, object>>(propertyCount);
|
||
|
|
||
|
if (this.via != null)
|
||
|
pairs.Add(new KeyValuePair<string, object>(ViaKey, via));
|
||
|
|
||
|
if (this.allowOutputBatching != null)
|
||
|
pairs.Add(new KeyValuePair<string, object>(AllowOutputBatchingKey, allowOutputBatching));
|
||
|
|
||
|
if (this.security != null)
|
||
|
pairs.Add(new KeyValuePair<string, object>(SecurityKey, security));
|
||
|
|
||
|
if (this.encoder != null)
|
||
|
pairs.Add(new KeyValuePair<string, object>(EncoderKey, encoder));
|
||
|
|
||
|
if (properties != null)
|
||
|
{
|
||
|
for (int i = 0; i < properties.Length; i++)
|
||
|
{
|
||
|
string propertyName = properties[i].Name;
|
||
|
|
||
|
if (propertyName == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pairs.Add(new KeyValuePair<string, object>(propertyName, properties[i].Value));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pairs.GetEnumerator();
|
||
|
}
|
||
|
|
||
|
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> pair)
|
||
|
{
|
||
|
if (disposed)
|
||
|
ThrowDisposed();
|
||
|
|
||
|
if (pair.Value == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
|
||
|
if (pair.Key == null)
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Key"));
|
||
|
|
||
|
object value;
|
||
|
if (!TryGetValue(pair.Key, out value))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (!value.Equals(pair.Value))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
Remove(pair.Key);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
struct Property : IDisposable
|
||
|
{
|
||
|
string name;
|
||
|
object value;
|
||
|
|
||
|
public Property(string name, object value)
|
||
|
{
|
||
|
this.name = name;
|
||
|
this.value = value;
|
||
|
}
|
||
|
|
||
|
public string Name
|
||
|
{
|
||
|
get { return name; }
|
||
|
}
|
||
|
|
||
|
public object Value
|
||
|
{
|
||
|
get { return value; }
|
||
|
set { this.value = value; }
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
IDisposable disposable = value as IDisposable;
|
||
|
if (disposable != null)
|
||
|
disposable.Dispose();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|