Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,269 @@
//------------------------------------------------------------------------------
// <copyright file="BitVector32.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System.Diagnostics;
using System.Text;
using System;
using Microsoft.Win32;
/// <devdoc>
/// <para>Provides a simple light bit vector with easy integer or Boolean access to
/// a 32 bit storage.</para>
/// </devdoc>
public struct BitVector32 {
private uint data;
/// <devdoc>
/// <para>Initializes a new instance of the BitVector32 structure with the specified internal data.</para>
/// </devdoc>
public BitVector32(int data) {
this.data = (uint)data;
}
/// <devdoc>
/// <para>Initializes a new instance of the BitVector32 structure with the information in the specified
/// value.</para>
/// </devdoc>
public BitVector32(BitVector32 value) {
this.data = value.data;
}
/// <devdoc>
/// <para>Gets or sets a value indicating whether all the specified bits are set.</para>
/// </devdoc>
public bool this[int bit] {
get {
return (data & bit) == (uint)bit;
}
set {
if (value) {
data |= (uint)bit;
}
else {
data &= ~(uint)bit;
}
}
}
/// <devdoc>
/// <para>Gets or sets the value for the specified section.</para>
/// </devdoc>
public int this[Section section] {
get {
return (int)((data & (uint)(section.Mask << section.Offset)) >> section.Offset);
}
set {
#if DEBUG
if ((value & section.Mask) != value) {
Debug.Fail("Value out of bounds on BitVector32 Section Set!");
}
#endif
value <<= section.Offset;
int offsetMask = (0xFFFF & (int)section.Mask) << section.Offset;
data = (data & ~(uint)offsetMask) | ((uint)value & (uint)offsetMask);
}
}
/// <devdoc>
/// returns the raw data stored in this bit vector...
/// </devdoc>
public int Data {
get {
return (int)data;
}
}
private static short CountBitsSet(short mask) {
// yes, I know there are better algorithms, however, we know the
// bits are always right aligned, with no holes (i.e. always 00000111,
// never 000100011), so this is just fine...
//
short value = 0;
while ((mask & 0x1) != 0) {
value++;
mask >>= 1;
}
return value;
}
/// <devdoc>
/// <para> Creates the first mask in a series.</para>
/// </devdoc>
public static int CreateMask() {
return CreateMask(0);
}
/// <devdoc>
/// Creates the next mask in a series.
/// </devdoc>
public static int CreateMask(int previous) {
if (previous == 0) {
return 1;
}
if (previous == unchecked((int)0x80000000)) {
throw new InvalidOperationException(SR.GetString(SR.BitVectorFull));
}
return previous << 1;
}
/// <devdoc>
/// Given a highValue, creates the mask
/// </devdoc>
private static short CreateMaskFromHighValue(short highValue) {
short required = 16;
while ((highValue & 0x8000) == 0) {
required--;
highValue <<= 1;
}
ushort value = 0;
while (required > 0) {
required--;
value <<= 1;
value |= 0x1;
}
return unchecked((short) value);
}
/// <devdoc>
/// <para>Creates the first section in a series, with the specified maximum value.</para>
/// </devdoc>
public static Section CreateSection(short maxValue) {
return CreateSectionHelper(maxValue, 0, 0);
}
/// <devdoc>
/// <para>Creates the next section in a series, with the specified maximum value.</para>
/// </devdoc>
public static Section CreateSection(short maxValue, Section previous) {
return CreateSectionHelper(maxValue, previous.Mask, previous.Offset);
}
private static Section CreateSectionHelper(short maxValue, short priorMask, short priorOffset) {
if (maxValue < 1) {
throw new ArgumentException(SR.GetString(SR.Argument_InvalidValue, "maxValue", 0), "maxValue");
}
#if DEBUG
int maskCheck = CreateMaskFromHighValue(maxValue);
int offsetCheck = priorOffset + CountBitsSet(priorMask);
Debug.Assert(maskCheck <= short.MaxValue && offsetCheck < 32, "Overflow on BitVector32");
#endif
short offset = (short)(priorOffset + CountBitsSet(priorMask));
if (offset >= 32) {
throw new InvalidOperationException(SR.GetString(SR.BitVectorFull));
}
return new Section(CreateMaskFromHighValue(maxValue), offset);
}
public override bool Equals(object o) {
if (!(o is BitVector32)) {
return false;
}
return data == ((BitVector32)o).data;
}
public override int GetHashCode() {
return base.GetHashCode();
}
/// <devdoc>
/// </devdoc>
public static string ToString(BitVector32 value) {
StringBuilder sb = new StringBuilder(/*"BitVector32{".Length*/12 + /*32 bits*/32 + /*"}".Length"*/1);
sb.Append("BitVector32{");
int locdata = (int)value.data;
for (int i=0; i<32; i++) {
if ((locdata & 0x80000000) != 0) {
sb.Append("1");
}
else {
sb.Append("0");
}
locdata <<= 1;
}
sb.Append("}");
return sb.ToString();
}
/// <devdoc>
/// </devdoc>
public override string ToString() {
return BitVector32.ToString(this);
}
/// <devdoc>
/// <para>
/// Represents an section of the vector that can contain a integer number.</para>
/// </devdoc>
public struct Section {
private readonly short mask;
private readonly short offset;
internal Section(short mask, short offset) {
this.mask = mask;
this.offset = offset;
}
public short Mask {
get {
return mask;
}
}
public short Offset {
get {
return offset;
}
}
public override bool Equals(object o) {
if (o is Section)
return Equals((Section)o);
else
return false;
}
public bool Equals(Section obj)
{
return obj.mask == mask && obj.offset == offset;
}
public static bool operator ==(Section a, Section b)
{
return a.Equals(b);
}
public static bool operator !=(Section a, Section b)
{
return !(a == b);
}
public override int GetHashCode() {
return base.GetHashCode();
}
/// <devdoc>
/// </devdoc>
public static string ToString(Section value) {
return "Section{0x" + Convert.ToString(value.Mask, 16) + ", 0x" + Convert.ToString(value.Offset, 16) + "}";
}
/// <devdoc>
/// </devdoc>
public override string ToString() {
return Section.ToString(this);
}
}
}
}

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
// <copyright file="CaseSensitiveStringDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
On UNIX systems the environment variable names are case sensitive (as the opposite from Windows).
Thus using StringDictionary to store the environment settings is wrong
(StringDictionary converts key values to lower case).
CaseSensitiveStringDictionary is derived from the StringDictionary and it does the same thing,
except the conversion of the key to lower case. So its fully usable for UNIX systems.
This class is used to create the StringDictionary object everywhere
its used for environment settings storage (only ProcessStartInfo.cs and Executor.cs).
This change enables the correct UNIX behavior along with not changing public API.
Author: vitkaras
*/
#if PLATFORM_UNIX
namespace System.Collections.Specialized
{
using System.Runtime.InteropServices;
using System.Diagnostics;
using System;
using System.Collections;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Security.Permissions;
// This subclass of StringDictionary ensures that we do the lookups in a case-sensitive manner,
// so we can match any string comparisons that are done on Unix.
internal class CaseSensitiveStringDictionary : StringDictionary
{
public CaseSensitiveStringDictionary () {
}
public override string this[ string key ]
{
get
{
if ( key == null )
{
throw new ArgumentNullException ( "key" );
}
return (string) contents[ key ];
}
set
{
if ( key == null )
{
throw new ArgumentNullException ( "key" );
}
contents[ key ] = value;
}
}
public override void Add ( string key, string value )
{
if ( key == null )
{
throw new ArgumentNullException ( "key" );
}
contents.Add ( key , value );
}
public override bool ContainsKey ( string key )
{
if ( key == null )
{
throw new ArgumentNullException ( "key" );
}
return contents.ContainsKey ( key );
}
public override void Remove ( string key )
{
if ( key == null )
{
throw new ArgumentNullException ( "key" );
}
contents.Remove ( key );
}
}
}
#endif // PLATFORM_UNIX

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// <copyright file="CollectionsUtil.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Wrapper for a case insensitive Hashtable.
namespace System.Collections.Specialized {
using System.Collections;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class CollectionsUtil {
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static Hashtable CreateCaseInsensitiveHashtable() {
return new Hashtable(StringComparer.CurrentCultureIgnoreCase);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static Hashtable CreateCaseInsensitiveHashtable(int capacity) {
return new Hashtable(capacity, StringComparer.CurrentCultureIgnoreCase);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static Hashtable CreateCaseInsensitiveHashtable(IDictionary d) {
return new Hashtable(d, StringComparer.CurrentCultureIgnoreCase);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static SortedList CreateCaseInsensitiveSortedList() {
return new SortedList(CaseInsensitiveComparer.Default);
}
}
}

View File

@@ -0,0 +1,124 @@
//------------------------------------------------------------------------------
// <copyright file="FixedStringLookup.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
// This class provides a very efficient way to lookup an entry in a list of strings,
// providing that they are declared in a particular way.
// It requires the set of strings to be orderded into an array of arrays of strings.
// The first indexer must the length of the string, so that each sub-array is of the
// same length. The contained array must be in alphabetical order. Furthermore, if the
// table is to be searched case-insensitively, the strings must all be lower case.
internal static class FixedStringLookup {
// Returns whether the match is found in the lookup table
internal static bool Contains(string[][] lookupTable, string value, bool ignoreCase) {
int length = value.Length;
if (length <= 0 || length - 1 >= lookupTable.Length) {
return false;
}
string[] subArray = lookupTable[length - 1];
if (subArray == null) {
return false;
}
return Contains(subArray, value, ignoreCase);
}
#if DEBUG
internal static void VerifyLookupTable(string[][] lookupTable, bool ignoreCase) {
for (int i = 0; i < lookupTable.Length; i++) {
string[] subArray = lookupTable[i];
if (subArray != null) {
string lastValue = null;
for (int j = 0; j < subArray.Length; j++) {
string value = subArray[j];
// Must all be the length of the hashed position
Debug.Assert(value.Length == i + 1, "Lookup table contains an item in the wrong subtable. Item name: " + value);
if (lastValue != null) {
// Must be sorted within the sub array;
Debug.Assert(string.Compare(lastValue, value, ((ignoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) < 0,
String.Format(CultureInfo.InvariantCulture, "Lookup table is out of order. Items {0} and {1} are reversed", lastValue, value));
}
lastValue = value;
}
}
}
}
#endif
// This routine finds a hit within a single sorted array, with the assumption that the
// value and all the strings are of the same length.
private static bool Contains(string[] array, string value, bool ignoreCase) {
int min = 0;
int max = array.Length;
int pos = 0;
char searchChar;
while (pos < value.Length) {
if (ignoreCase) {
searchChar = char.ToLower(value[pos], CultureInfo.InvariantCulture);
} else {
searchChar = value[pos];
}
if ((max - min) <= 1) {
// we are down to a single item, so we can stay on this row until the end.
if (searchChar != array[min][pos]) {
return false;
}
pos++;
continue;
}
// There are multiple items to search, use binary search to find one of the hits
if (!FindCharacter(array, searchChar, pos, ref min, ref max)) {
return false;
}
// and move to next char
pos++;
}
return true;
}
// Do a binary search on the character array at the specific position and constrict the ranges appropriately.
private static bool FindCharacter(string[] array, char value, int pos, ref int min, ref int max) {
int index = min;
while (min < max) {
index = (min + max) / 2;
char comp = array[index][pos];
if (value == comp) {
// We have a match. Now adjust to any adjacent matches
int newMin = index;
while (newMin > min && array[newMin - 1][pos] == value) {
newMin--;
}
min = newMin;
int newMax = index + 1;
while (newMax < max && array[newMax][pos] == value) {
newMax++;
}
max = newMax;
return true;
}
if (value < comp) {
max = index;
}
else {
min = index + 1;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,338 @@
//------------------------------------------------------------------------------
// <copyright file="HybridDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System.Collections;
using System.Globalization;
/// <devdoc>
/// <para>
/// This data structure implements IDictionary first using a linked list
/// (ListDictionary) and then switching over to use Hashtable when large. This is recommended
/// for cases where the number of elements in a dictionary is unknown and might be small.
///
/// It also has a single boolean parameter to allow case-sensitivity that is not affected by
/// ambient culture and has been optimized for looking up case-insensitive symbols
/// </para>
/// </devdoc>
[Serializable]
public class HybridDictionary: IDictionary {
// These numbers have been carefully tested to be optimal. Please don't change them
// without doing thorough performance testing.
private const int CutoverPoint = 9;
private const int InitialHashtableSize = 13;
private const int FixedSizeCutoverPoint = 6;
// Instance variables. This keeps the HybridDictionary very light-weight when empty
private ListDictionary list;
private Hashtable hashtable;
private bool caseInsensitive;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public HybridDictionary() {
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public HybridDictionary(int initialSize) : this(initialSize, false) {
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public HybridDictionary(bool caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public HybridDictionary(int initialSize, bool caseInsensitive) {
this.caseInsensitive = caseInsensitive;
if (initialSize >= FixedSizeCutoverPoint) {
if (caseInsensitive) {
hashtable = new Hashtable(initialSize, StringComparer.OrdinalIgnoreCase);
} else {
hashtable = new Hashtable(initialSize);
}
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public object this[object key] {
get {
// <
ListDictionary cachedList = list;
if (hashtable != null) {
return hashtable[key];
} else if (cachedList != null) {
return cachedList[key];
} else {
// <
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
return null;
}
}
set {
if (hashtable != null) {
hashtable[key] = value;
}
else if (list != null) {
if (list.Count >= CutoverPoint - 1) {
ChangeOver();
hashtable[key] = value;
} else {
list[key] = value;
}
}
else {
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
list[key] = value;
}
}
}
private ListDictionary List {
get {
if (list == null) {
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
}
return list;
}
}
private void ChangeOver() {
IDictionaryEnumerator en = list.GetEnumerator();
Hashtable newTable;
if (caseInsensitive) {
newTable = new Hashtable(InitialHashtableSize, StringComparer.OrdinalIgnoreCase);
} else {
newTable = new Hashtable(InitialHashtableSize);
}
while (en.MoveNext()) {
newTable.Add(en.Key, en.Value);
}
// <
hashtable = newTable;
list = null;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int Count {
get {
ListDictionary cachedList = list;
if (hashtable != null) {
return hashtable.Count;
} else if (cachedList != null) {
return cachedList.Count;
} else {
return 0;
}
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ICollection Keys {
get {
if (hashtable != null) {
return hashtable.Keys;
} else {
return List.Keys;
}
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsFixedSize {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public object SyncRoot {
get {
return this;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ICollection Values {
get {
if (hashtable != null) {
return hashtable.Values;
} else {
return List.Values;
}
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Add(object key, object value) {
if (hashtable != null) {
hashtable.Add(key, value);
} else {
if (list == null) {
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
list.Add(key, value);
}
else {
if (list.Count + 1 >= CutoverPoint) {
ChangeOver();
hashtable.Add(key, value);
} else {
list.Add(key, value);
}
}
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Clear() {
if(hashtable != null) {
Hashtable cachedHashtable = hashtable;
hashtable = null;
cachedHashtable.Clear();
}
if( list != null) {
ListDictionary cachedList = list;
list = null;
cachedList.Clear();
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool Contains(object key) {
ListDictionary cachedList = list;
if (hashtable != null) {
return hashtable.Contains(key);
} else if (cachedList != null) {
return cachedList.Contains(key);
} else {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void CopyTo(Array array, int index) {
if (hashtable != null) {
hashtable.CopyTo(array, index);
} else {
List.CopyTo(array, index);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public IDictionaryEnumerator GetEnumerator() {
if (hashtable != null) {
return hashtable.GetEnumerator();
}
if (list == null) {
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
}
return list.GetEnumerator();
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
IEnumerator IEnumerable.GetEnumerator() {
if (hashtable != null) {
return hashtable.GetEnumerator();
}
if (list == null) {
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
}
return list.GetEnumerator();
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Remove(object key) {
if (hashtable != null) {
hashtable.Remove(key);
}
else if (list != null){
list.Remove(key);
}
else {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
}
}
}
}

View File

@@ -0,0 +1,40 @@
//---------------------------------------------------------------------------
//
// <copyright file="INotifyCollectionChanged.cs" company="Microsoft">
// Copyright (C) 2003 by Microsoft Corporation. All rights reserved.
// </copyright>
//
//
// Description: Allows collections to notify listeners of dynamic updates.
//
// See spec at http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
//
//---------------------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
namespace System.Collections.Specialized
{
/// <summary>
/// A collection implementing this interface will notify listeners of dynamic changes,
/// e.g. when items get added and removed or the whole list is refreshed.
/// </summary>
#if !MOBILE
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
#endif
public interface INotifyCollectionChanged
{
/// <summary>
/// Occurs when the collection changes, either by adding or removing an item.
/// </summary>
/// <remarks>
/// The event handler receives an argument of type
/// <seealso cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" />
/// containing data related to this event.
/// </remarks>
event NotifyCollectionChangedEventHandler CollectionChanged;
}
}

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
// <copyright file="IOrderedDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System;
using System.Collections;
/// <devdoc>
/// <para>
/// This interface adds indexing on the IDictionary keyed table concept. Objects
/// added or inserted in an IOrderedDictionary must have both a key and an index, and
/// can be retrieved by either.
/// This interface is useful when preserving easy IDictionary access semantics via a key is
/// desired while ordering is necessary.
/// </para>
/// </devdoc>
public interface IOrderedDictionary : IDictionary {
// properties
/// <devdoc>
/// Returns the object at the given index
/// </devdoc>
object this[int index] { get; set; }
// Returns an IDictionaryEnumerator for this dictionary.
new IDictionaryEnumerator GetEnumerator();
// methods
/// <devdoc>
/// Inserts the given object, with the given key, at the given index
/// </devdoc>
void Insert(int index, object key, object value);
/// <devdoc>
/// Removes the object and key at the given index
/// </devdoc>
void RemoveAt(int index);
}
}

View File

@@ -0,0 +1,455 @@
//------------------------------------------------------------------------------
// <copyright file="ListDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System.Collections;
using Microsoft.Win32;
/// <devdoc>
/// <para>
/// This is a simple implementation of IDictionary using a singly linked list. This
/// will be smaller and faster than a Hashtable if the number of elements is 10 or less.
/// This should not be used if performance is important for large numbers of elements.
/// </para>
/// </devdoc>
[Serializable]
public class ListDictionary: IDictionary {
DictionaryNode head;
int version;
int count;
IComparer comparer;
[NonSerialized]
private Object _syncRoot;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListDictionary() {
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListDictionary(IComparer comparer) {
this.comparer = comparer;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public object this[object key] {
get {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
DictionaryNode node = head;
if (comparer == null) {
while (node != null) {
object oldKey = node.key;
if ( oldKey!= null && oldKey.Equals(key)) {
return node.value;
}
node = node.next;
}
}
else {
while (node != null) {
object oldKey = node.key;
if (oldKey != null && comparer.Compare(oldKey, key) == 0) {
return node.value;
}
node = node.next;
}
}
return null;
}
set {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
version++;
DictionaryNode last = null;
DictionaryNode node;
for (node = head; node != null; node = node.next) {
object oldKey = node.key;
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
break;
}
last = node;
}
if (node != null) {
// Found it
node.value = value;
return;
}
// Not found, so add a new one
DictionaryNode newNode = new DictionaryNode();
newNode.key = key;
newNode.value = value;
if (last != null) {
last.next = newNode;
}
else {
head = newNode;
}
count++;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int Count {
get {
return count;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ICollection Keys {
get {
return new NodeKeyValueCollection(this, true);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsFixedSize {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public object SyncRoot {
get {
if( _syncRoot == null) {
System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null);
}
return _syncRoot;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ICollection Values {
get {
return new NodeKeyValueCollection(this, false);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Add(object key, object value) {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
version++;
DictionaryNode last = null;
DictionaryNode node;
for (node = head; node != null; node = node.next) {
object oldKey = node.key;
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
throw new ArgumentException(SR.GetString(SR.Argument_AddingDuplicate));
}
last = node;
}
// Not found, so add a new one
DictionaryNode newNode = new DictionaryNode();
newNode.key = key;
newNode.value = value;
if (last != null) {
last.next = newNode;
}
else {
head = newNode;
}
count++;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Clear() {
count = 0;
head = null;
version++;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool Contains(object key) {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
for (DictionaryNode node = head; node != null; node = node.next) {
object oldKey = node.key;
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
return true;
}
}
return false;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void CopyTo(Array array, int index) {
if (array==null)
throw new ArgumentNullException("array");
if (index < 0)
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
if (array.Length - index < count)
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
for (DictionaryNode node = head; node != null; node = node.next) {
array.SetValue(new DictionaryEntry(node.key, node.value), index);
index++;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public IDictionaryEnumerator GetEnumerator() {
return new NodeEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator() {
return new NodeEnumerator(this);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Remove(object key) {
if (key == null) {
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
}
version++;
DictionaryNode last = null;
DictionaryNode node;
for (node = head; node != null; node = node.next) {
object oldKey = node.key;
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
break;
}
last = node;
}
if (node == null) {
return;
}
if (node == head) {
head = node.next;
} else {
last.next = node.next;
}
count--;
}
private class NodeEnumerator : IDictionaryEnumerator {
ListDictionary list;
DictionaryNode current;
int version;
bool start;
public NodeEnumerator(ListDictionary list) {
this.list = list;
version = list.version;
start = true;
current = null;
}
public object Current {
get {
return Entry;
}
}
public DictionaryEntry Entry {
get {
if (current == null) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
}
return new DictionaryEntry(current.key, current.value);
}
}
public object Key {
get {
if (current == null) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
}
return current.key;
}
}
public object Value {
get {
if (current == null) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
}
return current.value;
}
}
public bool MoveNext() {
if (version != list.version) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
}
if (start) {
current = list.head;
start = false;
}
else if (current != null) {
current = current.next;
}
return (current != null);
}
public void Reset() {
if (version != list.version) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
}
start = true;
current = null;
}
}
private class NodeKeyValueCollection : ICollection {
ListDictionary list;
bool isKeys;
public NodeKeyValueCollection(ListDictionary list, bool isKeys) {
this.list = list;
this.isKeys = isKeys;
}
void ICollection.CopyTo(Array array, int index) {
if (array==null)
throw new ArgumentNullException("array");
if (index < 0)
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
for (DictionaryNode node = list.head; node != null; node = node.next) {
array.SetValue(isKeys ? node.key : node.value, index);
index++;
}
}
int ICollection.Count {
get {
int count = 0;
for (DictionaryNode node = list.head; node != null; node = node.next) {
count++;
}
return count;
}
}
bool ICollection.IsSynchronized {
get {
return false;
}
}
object ICollection.SyncRoot {
get {
return list.SyncRoot;
}
}
IEnumerator IEnumerable.GetEnumerator() {
return new NodeKeyValueEnumerator(list, isKeys);
}
private class NodeKeyValueEnumerator: IEnumerator {
ListDictionary list;
DictionaryNode current;
int version;
bool isKeys;
bool start;
public NodeKeyValueEnumerator(ListDictionary list, bool isKeys) {
this.list = list;
this.isKeys = isKeys;
this.version = list.version;
this.start = true;
this.current = null;
}
public object Current {
get {
if (current == null) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
}
return isKeys ? current.key : current.value;
}
}
public bool MoveNext() {
if (version != list.version) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
}
if (start) {
current = list.head;
start = false;
}
else if (current != null) {
current = current.next;
}
return (current != null);
}
public void Reset() {
if (version != list.version) {
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
}
start = true;
current = null;
}
}
}
[Serializable]
private class DictionaryNode {
public object key;
public object value;
public DictionaryNode next;
}
}
}

View File

@@ -0,0 +1,485 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// <OWNER>[....]</OWNER>
using System.Security;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Collections.Specialized;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace System.Runtime.InteropServices.WindowsRuntime
{
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChangedEventArgs
[ComImport]
[Guid("4cf68d33-e3f2-4964-b85e-945b4f7e2f21")]
[WindowsRuntimeImport]
internal interface INotifyCollectionChangedEventArgs
{
NotifyCollectionChangedAction Action { get; }
IList NewItems { get; }
IList OldItems { get; }
int NewStartingIndex { get; }
int OldStartingIndex { get; }
}
// Local definition of Windows.UI.Xaml.Data.IPropertyChangedEventArgs
[ComImport]
[Guid("4f33a9a0-5cf4-47a4-b16f-d7faaf17457e")]
[WindowsRuntimeImport]
internal interface IPropertyChangedEventArgs
{
string PropertyName { get; }
}
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChanged
[ComImport]
[Guid("28b167d5-1a31-465b-9b25-d5c3ae686c40")]
[WindowsRuntimeImport]
internal interface INotifyCollectionChanged_WinRT
{
EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value);
void remove_CollectionChanged(EventRegistrationToken token);
}
// Local definition of Windows.UI.Xaml.Data.INotifyPropertyChanged
[ComImport]
[Guid("cf75d69c-f2f4-486b-b302-bb4c09baebfa")]
[WindowsRuntimeImport]
internal interface INotifyPropertyChanged_WinRT
{
EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value);
void remove_PropertyChanged(EventRegistrationToken token);
}
// Local definition of Windows.UI.Xaml.Input.ICommand
[ComImport]
[Guid("e5af3542-ca67-4081-995b-709dd13792df")]
[WindowsRuntimeImport]
internal interface ICommand_WinRT
{
EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value);
void remove_CanExecuteChanged(EventRegistrationToken token);
bool CanExecute(object parameter);
void Execute(object parameter);
}
// Local definition of Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler
[Guid("ca10b37c-f382-4591-8557-5e24965279b0")]
[WindowsRuntimeImport]
internal delegate void NotifyCollectionChangedEventHandler_WinRT(object sender, NotifyCollectionChangedEventArgs e);
// Local definition of Windows.UI.Xaml.Data.PropertyChangedEventHandler
[Guid("50f19c16-0a22-4d8e-a089-1ea9951657d2")]
[WindowsRuntimeImport]
internal delegate void PropertyChangedEventHandler_WinRT(object sender, PropertyChangedEventArgs e);
internal static class NotifyCollectionChangedEventArgsMarshaler
{
// Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to
// a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance.
// This method is called from IL stubs and needs to have its token stabilized.
[SecurityCritical]
static internal IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedArgs)
{
if (managedArgs == null)
return IntPtr.Zero;
return System.StubHelpers.EventArgsMarshaler.CreateNativeNCCEventArgsInstance(
(int)managedArgs.Action,
managedArgs.NewItems,
managedArgs.OldItems,
managedArgs.NewStartingIndex,
managedArgs.OldStartingIndex);
}
// Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new
// managed NotifyCollectionChangedEventArgs instance.
// This method is called from IL stubs and needs to have its token stabilized.
[SecurityCritical]
static internal NotifyCollectionChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
{
if (nativeArgsIP == IntPtr.Zero)
return null;
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
INotifyCollectionChangedEventArgs nativeArgs = (INotifyCollectionChangedEventArgs)obj;
return new NotifyCollectionChangedEventArgs(
nativeArgs.Action,
nativeArgs.NewItems,
nativeArgs.OldItems,
nativeArgs.NewStartingIndex,
nativeArgs.OldStartingIndex);
}
}
internal static class PropertyChangedEventArgsMarshaler
{
// Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to
// a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance.
// This method is called from IL stubs and needs to have its token stabilized.
[SecurityCritical]
static internal IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs)
{
if (managedArgs == null)
return IntPtr.Zero;
return System.StubHelpers.EventArgsMarshaler.CreateNativePCEventArgsInstance(managedArgs.PropertyName);
}
// Extracts properties from a WinRT PropertyChangedEventArgs and creates a new
// managed PropertyChangedEventArgs instance.
// This method is called from IL stubs and needs to have its token stabilized.
[SecurityCritical]
static internal PropertyChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
{
if (nativeArgsIP == IntPtr.Zero)
return null;
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
IPropertyChangedEventArgs nativeArgs = (IPropertyChangedEventArgs)obj;
return new PropertyChangedEventArgs(nativeArgs.PropertyName);
}
}
// This is a set of stub methods implementing the support for the managed INotifyCollectionChanged
// interface on WinRT objects that support the WinRT INotifyCollectionChanged. Used by the interop
// mashaling infrastructure.
internal sealed class NotifyCollectionChangedToManagedAdapter
{
private NotifyCollectionChangedToManagedAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
internal event NotifyCollectionChangedEventHandler CollectionChanged
{
// void CollectionChanged.add(NotifyCollectionChangedEventHandler)
[SecurityCritical]
add
{
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
// call the WinRT eventing support in mscorlib to subscribe the event
Func<NotifyCollectionChangedEventHandler, EventRegistrationToken> addMethod =
new Func<NotifyCollectionChangedEventHandler, EventRegistrationToken>(_this.add_CollectionChanged);
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
WindowsRuntimeMarshal.AddEventHandler<NotifyCollectionChangedEventHandler>(addMethod, removeMethod, value);
}
// void CollectionChanged.remove(NotifyCollectionChangedEventHandler)
[SecurityCritical]
remove
{
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
// call the WinRT eventing support in mscorlib to unsubscribe the event
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
WindowsRuntimeMarshal.RemoveEventHandler<NotifyCollectionChangedEventHandler>(removeMethod, value);
}
}
}
// This is a set of stub methods implementing the support for the WinRT INotifyCollectionChanged
// interface on managed objects that support the managed INotifyCollectionChanged. Used by the interop
// mashaling infrastructure.
internal sealed class NotifyCollectionChangedToWinRTAdapter
{
private NotifyCollectionChangedToWinRTAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
// separately, associated with the implementations using ConditionalWeakTable.
private static ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>> m_weakTable =
new ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>>();
// EventRegistrationToken CollectionChanged.add(NotifyCollectionChangedEventHandler value)
[SecurityCritical]
internal EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value)
{
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
EventRegistrationToken token = table.AddEventHandler(value);
_this.CollectionChanged += value;
return token;
}
// void CollectionChanged.remove(EventRegistrationToken token)
[SecurityCritical]
internal void remove_CollectionChanged(EventRegistrationToken token)
{
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
NotifyCollectionChangedEventHandler handler = table.ExtractHandler(token);
if (handler != null)
{
_this.CollectionChanged -= handler;
}
}
}
// This is a set of stub methods implementing the support for the managed INotifyPropertyChanged
// interface on WinRT objects that support the WinRT INotifyPropertyChanged. Used by the interop
// mashaling infrastructure.
internal sealed class NotifyPropertyChangedToManagedAdapter
{
private NotifyPropertyChangedToManagedAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
internal event PropertyChangedEventHandler PropertyChanged
{
// void PropertyChanged.add(PropertyChangedEventHandler)
[SecurityCritical]
add
{
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
// call the WinRT eventing support in mscorlib to subscribe the event
Func<PropertyChangedEventHandler, EventRegistrationToken> addMethod =
new Func<PropertyChangedEventHandler, EventRegistrationToken>(_this.add_PropertyChanged);
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
WindowsRuntimeMarshal.AddEventHandler<PropertyChangedEventHandler>(addMethod, removeMethod, value);
}
// void PropertyChanged.remove(PropertyChangedEventHandler)
[SecurityCritical]
remove
{
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
// call the WinRT eventing support in mscorlib to unsubscribe the event
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
WindowsRuntimeMarshal.RemoveEventHandler<PropertyChangedEventHandler>(removeMethod, value);
}
}
}
// This is a set of stub methods implementing the support for the WinRT INotifyPropertyChanged
// interface on managed objects that support the managed INotifyPropertyChanged. Used by the interop
// mashaling infrastructure.
internal sealed class NotifyPropertyChangedToWinRTAdapter
{
private NotifyPropertyChangedToWinRTAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
// separately, associated with the implementations using ConditionalWeakTable.
private static ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>> m_weakTable =
new ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>>();
// EventRegistrationToken PropertyChanged.add(PropertyChangedEventHandler value)
[SecurityCritical]
internal EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value)
{
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
EventRegistrationToken token = table.AddEventHandler(value);
_this.PropertyChanged += value;
return token;
}
// void PropertyChanged.remove(EventRegistrationToken token)
[SecurityCritical]
internal void remove_PropertyChanged(EventRegistrationToken token)
{
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
PropertyChangedEventHandler handler = table.ExtractHandler(token);
if (handler != null)
{
_this.PropertyChanged -= handler;
}
}
}
// This is a set of stub methods implementing the support for the managed ICommand
// interface on WinRT objects that support the WinRT ICommand_WinRT.
// Used by the interop mashaling infrastructure.
// Instances of this are really RCWs of ICommand_WinRT (not ICommandToManagedAdapter or any ICommand).
[SecurityCritical]
internal sealed class ICommandToManagedAdapter /*: System.Windows.Input.ICommand*/
{
private static ConditionalWeakTable<EventHandler, EventHandler<object>> m_weakTable =
new ConditionalWeakTable<EventHandler, EventHandler<object>>();
private ICommandToManagedAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
private event EventHandler CanExecuteChanged
{
// void CanExecuteChanged.add(EventHandler)
add
{
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
// call the WinRT eventing support in mscorlib to subscribe the event
Func<EventHandler<object>, EventRegistrationToken> addMethod =
new Func<EventHandler<object>, EventRegistrationToken>(_this.add_CanExecuteChanged);
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.AddEventHandler)
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
EventHandler<object> handler_WinRT = m_weakTable.GetValue(value, ICommandAdapterHelpers.CreateWrapperHandler);
WindowsRuntimeMarshal.AddEventHandler<EventHandler<object>>(addMethod, removeMethod, handler_WinRT);
}
// void CanExecuteChanged.remove(EventHandler)
remove
{
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
// call the WinRT eventing support in mscorlib to unsubscribe the event
Action<EventRegistrationToken> removeMethod =
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.RemoveEventHandler)
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
// Also we do a value check rather than an instance check to ensure that different instances of the same delegates are treated equal.
EventHandler<object> handler_WinRT = ICommandAdapterHelpers.GetValueFromEquivalentKey(m_weakTable , value, ICommandAdapterHelpers.CreateWrapperHandler);
WindowsRuntimeMarshal.RemoveEventHandler<EventHandler<object>>(removeMethod, handler_WinRT);
}
}
private bool CanExecute(object parameter)
{
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
return _this.CanExecute(parameter);
}
private void Execute(object parameter)
{
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
_this.Execute(parameter);
}
}
// This is a set of stub methods implementing the support for the WinRT ICommand_WinRT
// interface on managed objects that support the managed ICommand interface.
// Used by the interop mashaling infrastructure.
// Instances of this are really CCWs of ICommand (not ICommandToWinRTAdapter or any ICommand_WinRT).
[SecurityCritical]
internal sealed class ICommandToWinRTAdapter /*: ICommand_WinRT*/
{
private ICommandToWinRTAdapter()
{
Contract.Assert(false, "This class is never instantiated");
}
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
// Since here the class can be an arbitrary implementation of ICommand, we have to keep the EventRegistrationTokenTable's
// separately, associated with the implementations using ConditionalWeakTable.
private static ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>> m_weakTable =
new ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>>();
// EventRegistrationToken PropertyChanged.add(EventHandler<object> value)
private EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value)
{
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
EventHandler handler = ICommandAdapterHelpers.CreateWrapperHandler(value);
EventRegistrationToken token = table.AddEventHandler(handler);
_this.CanExecuteChanged += handler;
return token;
}
// void PropertyChanged.remove(EventRegistrationToken token)
private void remove_CanExecuteChanged(EventRegistrationToken token)
{
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
EventHandler handler = table.ExtractHandler(token);
if (handler != null)
{
_this.CanExecuteChanged -= handler;
}
}
private bool CanExecute(object parameter)
{
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
return _this.CanExecute(parameter);
}
private void Execute(object parameter)
{
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
_this.Execute(parameter);
}
}
// A couple of ICommand adapter helpers need to be transparent, and so are in their own type
internal static class ICommandAdapterHelpers
{
internal static EventHandler<object> CreateWrapperHandler(EventHandler handler)
{
// Check whether it is a round-tripping case i.e. the sender is of the type eventArgs,
// If so we use it else we pass EventArgs.Empty
return (object sender, object e) =>
{
EventArgs eventArgs = e as EventArgs;
handler(sender, (eventArgs == null ? System.EventArgs.Empty : eventArgs));
};
}
internal static EventHandler CreateWrapperHandler(EventHandler<object> handler)
{
return (object sender, EventArgs e) => handler(sender, e);
}
internal static EventHandler<object> GetValueFromEquivalentKey(
ConditionalWeakTable<EventHandler, EventHandler<object>> table,
EventHandler key,
ConditionalWeakTable<EventHandler, EventHandler<object>>.CreateValueCallback callback)
{
EventHandler<object> value;
// Find the key in the table using a value check rather than an instance check.
EventHandler existingKey = table.FindEquivalentKeyUnsafe(key, out value);
if (existingKey == null)
{
value = callback(key);
table.Add(key, value);
}
return value;
}
}
}

View File

@@ -0,0 +1,395 @@
//------------------------------------------------------------------------------
// <copyright file="NameValueCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Ordered String/String[] collection of name/value pairs with support for null key
* Wraps NameObject collection
*
* Copyright (c) 2000 Microsoft Corporation
*/
namespace System.Collections.Specialized {
using Microsoft.Win32;
using System.Collections;
using System.Runtime.Serialization;
using System.Text;
using System.Globalization;
/// <devdoc>
/// <para>Represents a sorted collection of associated <see cref='System.String' qualify='true'/> keys and <see cref='System.String' qualify='true'/> values that
/// can be accessed either with the hash code of the key or with the index.</para>
/// </devdoc>
[Serializable()]
public class NameValueCollection : NameObjectCollectionBase {
private String[] _all;
private String[] _allKeys;
//
// Constructors
//
/// <devdoc>
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the default initial capacity
/// and using the default case-insensitive hash code provider and the default
/// case-insensitive comparer.</para>
/// </devdoc>
public NameValueCollection() : base() {
}
/// <devdoc>
/// <para>Copies the entries from the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to a new <see cref='System.Collections.Specialized.NameValueCollection'/> with the same initial capacity as
/// the number of entries copied and using the default case-insensitive hash code
/// provider and the default case-insensitive comparer.</para>
/// </devdoc>
public NameValueCollection(NameValueCollection col)
: base( col != null? col.Comparer : null) {
Add(col);
}
/// <devdoc>
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the default initial capacity
/// and using the specified case-insensitive hash code provider and the specified
/// case-insensitive comparer.</para>
/// </devdoc>
#pragma warning disable 618
[Obsolete("Please use NameValueCollection(IEqualityComparer) instead.")]
public NameValueCollection(IHashCodeProvider hashProvider, IComparer comparer)
: base(hashProvider, comparer) {
}
#pragma warning restore 618
/// <devdoc>
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with
/// the specified initial capacity and using the default case-insensitive hash code
/// provider and the default case-insensitive comparer.</para>
/// </devdoc>
public NameValueCollection(int capacity) : base(capacity) {
}
public NameValueCollection(IEqualityComparer equalityComparer) : base( equalityComparer) {
}
public NameValueCollection(Int32 capacity, IEqualityComparer equalityComparer)
: base(capacity, equalityComparer) {
}
/// <devdoc>
/// <para>Copies the entries from the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to a new <see cref='System.Collections.Specialized.NameValueCollection'/> with the specified initial capacity or the
/// same initial capacity as the number of entries copied, whichever is greater, and
/// using the default case-insensitive hash code provider and the default
/// case-insensitive comparer.</para>
/// </devdoc>
public NameValueCollection(int capacity, NameValueCollection col)
: base(capacity, (col != null ? col.Comparer : null)) {
if( col == null) {
throw new ArgumentNullException("col");
}
this.Comparer = col.Comparer;
Add(col);
}
/// <devdoc>
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the specified initial capacity and
/// using the specified case-insensitive hash code provider and the specified
/// case-insensitive comparer.</para>
/// </devdoc>
#pragma warning disable 618
[Obsolete("Please use NameValueCollection(Int32, IEqualityComparer) instead.")]
public NameValueCollection(int capacity, IHashCodeProvider hashProvider, IComparer comparer)
: base(capacity, hashProvider, comparer) {
}
#pragma warning restore 618
// Allow internal extenders to avoid creating the hashtable/arraylist.
internal NameValueCollection(DBNull dummy) : base(dummy)
{
}
//
// Serialization support
//
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected NameValueCollection(SerializationInfo info, StreamingContext context) : base(info, context) {
}
//
// Helper methods
//
/// <devdoc>
/// <para> Resets the cached arrays of the collection to <see langword='null'/>.</para>
/// </devdoc>
protected void InvalidateCachedArrays() {
_all = null;
_allKeys = null;
}
private static String GetAsOneString(ArrayList list) {
int n = (list != null) ? list.Count : 0;
if (n == 1) {
return (String)list[0];
}
else if (n > 1) {
StringBuilder s = new StringBuilder((String)list[0]);
for (int i = 1; i < n; i++) {
s.Append(',');
s.Append((String)list[i]);
}
return s.ToString();
}
else {
return null;
}
}
private static String[] GetAsStringArray(ArrayList list)
{
int n = (list != null) ? list.Count : 0;
if (n == 0)
return null;
String [] array = new String[n];
list.CopyTo(0, array, 0, n);
return array;
}
//
// Misc public APIs
//
/// <devdoc>
/// <para>Copies the entries in the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to the current <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public void Add(NameValueCollection c) {
if( c == null) {
throw new ArgumentNullException("c");
}
InvalidateCachedArrays();
int n = c.Count;
for (int i = 0; i < n; i++) {
String key = c.GetKey(i);
String[] values = c.GetValues(i);
if (values != null) {
for (int j = 0; j < values.Length; j++)
Add(key, values[j]);
}
else {
Add(key, null);
}
}
}
/// <devdoc>
/// <para>Invalidates the cached arrays and removes all entries
/// from the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual void Clear() {
if (IsReadOnly)
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
InvalidateCachedArrays();
BaseClear();
}
public void CopyTo(Array dest, int index) {
if (dest==null) {
throw new ArgumentNullException("dest");
}
if (dest.Rank != 1) {
throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
}
if (index < 0) {
throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) );
}
if (dest.Length - index < Count) {
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
}
int n = Count;
if (_all == null) {
String[] all = new String[n];
for (int i = 0; i < n; i++) {
all[i] = Get(i);
dest.SetValue( all[i], i + index);
}
_all = all; // wait until end of loop to set _all reference in case Get throws
}
else {
for (int i = 0; i < n; i++) {
dest.SetValue( _all[i], i + index);
}
}
}
/// <devdoc>
/// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.NameValueCollection'/> contains entries whose keys are not <see langword='null'/>.</para>
/// </devdoc>
public bool HasKeys() {
return InternalHasKeys();
}
/// <devdoc>
/// <para>Allows derived classes to alter HasKeys().</para>
/// </devdoc>
internal virtual bool InternalHasKeys()
{
return BaseHasKeys();
}
//
// Access by name
//
/// <devdoc>
/// <para>Adds an entry with the specified name and value into the
/// <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual void Add(String name, String value) {
if (IsReadOnly)
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
InvalidateCachedArrays();
ArrayList values = (ArrayList)BaseGet(name);
if (values == null) {
// new key - add new key with single value
values = new ArrayList(1);
if (value != null)
values.Add(value);
BaseAdd(name, values);
}
else {
// old key -- append value to the list of values
if (value != null)
values.Add(value);
}
}
/// <devdoc>
/// <para> Gets the values associated with the specified key from the <see cref='System.Collections.Specialized.NameValueCollection'/> combined into one comma-separated list.</para>
/// </devdoc>
public virtual String Get(String name) {
ArrayList values = (ArrayList)BaseGet(name);
return GetAsOneString(values);
}
/// <devdoc>
/// <para>Gets the values associated with the specified key from the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual String[] GetValues(String name) {
ArrayList values = (ArrayList)BaseGet(name);
return GetAsStringArray(values);
}
/// <devdoc>
/// <para>Adds a value to an entry in the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual void Set(String name, String value) {
if (IsReadOnly)
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
InvalidateCachedArrays();
ArrayList values = new ArrayList(1);
values.Add(value);
BaseSet(name, values);
}
/// <devdoc>
/// <para>Removes the entries with the specified key from the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
/// </devdoc>
public virtual void Remove(String name) {
InvalidateCachedArrays();
BaseRemove(name);
}
/// <devdoc>
/// <para> Represents the entry with the specified key in the
/// <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public String this[String name] {
get {
return Get(name);
}
set {
Set(name, value);
}
}
//
// Indexed access
//
/// <devdoc>
/// <para>
/// Gets the values at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/> combined into one
/// comma-separated list.</para>
/// </devdoc>
public virtual String Get(int index) {
ArrayList values = (ArrayList)BaseGet(index);
return GetAsOneString(values);
}
/// <devdoc>
/// <para> Gets the values at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual String[] GetValues(int index) {
ArrayList values = (ArrayList)BaseGet(index);
return GetAsStringArray(values);
}
/// <devdoc>
/// <para>Gets the key at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public virtual String GetKey(int index) {
return BaseGetKey(index);
}
/// <devdoc>
/// <para>Represents the entry at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
/// </devdoc>
public String this[int index] {
get {
return Get(index);
}
}
//
// Access to keys and values as arrays
//
/// <devdoc>
/// <para>Gets all the keys in the <see cref='System.Collections.Specialized.NameValueCollection'/>. </para>
/// </devdoc>
public virtual String[] AllKeys {
get {
if (_allKeys == null)
_allKeys = BaseGetAllKeys();
return _allKeys;
}
}
}
}

View File

@@ -0,0 +1,419 @@
//---------------------------------------------------------------------------
//
// <copyright file="NotifyCollectionChangedEventArgs.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved.
// </copyright>
//
// Description: NotifyCollectionChanged event arguments
//
// Specs: http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
namespace System.Collections.Specialized
{
/// <summary>
/// This enum describes the action that caused a CollectionChanged event.
/// </summary>
#if !MOBILE
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
#endif
public enum NotifyCollectionChangedAction
{
/// <summary> One or more items were added to the collection. </summary>
Add,
/// <summary> One or more items were removed from the collection. </summary>
Remove,
/// <summary> One or more items were replaced in the collection. </summary>
Replace,
/// <summary> One or more items were moved within the collection. </summary>
Move,
/// <summary> The contents of the collection changed dramatically. </summary>
Reset,
}
/// <summary>
/// Arguments for the CollectionChanged event.
/// A collection that supports INotifyCollectionChangedThis raises this event
/// whenever an item is added or removed, or when the contents of the collection
/// changes dramatically.
/// </summary>
#if !MOBILE
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
#endif
public class NotifyCollectionChangedEventArgs : EventArgs
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a reset change.
/// </summary>
/// <param name="action">The action that caused the event (must be Reset).</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
{
if (action != NotifyCollectionChangedAction.Reset)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Reset), "action");
InitializeAdd(action, null, -1);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
/// </summary>
/// <param name="action">The action that caused the event; can only be Reset, Add or Remove action.</param>
/// <param name="changedItem">The item affected by the change.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
{
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
&& (action != NotifyCollectionChangedAction.Reset))
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
if (action == NotifyCollectionChangedAction.Reset)
{
if (changedItem != null)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
InitializeAdd(action, null, -1);
}
else
{
InitializeAddOrRemove(action, new object[]{changedItem}, -1);
}
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
/// </summary>
/// <param name="action">The action that caused the event.</param>
/// <param name="changedItem">The item affected by the change.</param>
/// <param name="index">The index where the change occurred.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
{
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
&& (action != NotifyCollectionChangedAction.Reset))
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
if (action == NotifyCollectionChangedAction.Reset)
{
if (changedItem != null)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
if (index != -1)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
InitializeAdd(action, null, -1);
}
else
{
InitializeAddOrRemove(action, new object[]{changedItem}, index);
}
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change.
/// </summary>
/// <param name="action">The action that caused the event.</param>
/// <param name="changedItems">The items affected by the change.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
{
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
&& (action != NotifyCollectionChangedAction.Reset))
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
if (action == NotifyCollectionChangedAction.Reset)
{
if (changedItems != null)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
InitializeAdd(action, null, -1);
}
else
{
if (changedItems == null)
throw new ArgumentNullException("changedItems");
InitializeAddOrRemove(action, changedItems, -1);
}
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change (or a reset).
/// </summary>
/// <param name="action">The action that caused the event.</param>
/// <param name="changedItems">The items affected by the change.</param>
/// <param name="startingIndex">The index where the change occurred.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
{
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
&& (action != NotifyCollectionChangedAction.Reset))
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
if (action == NotifyCollectionChangedAction.Reset)
{
if (changedItems != null)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
if (startingIndex != -1)
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
InitializeAdd(action, null, -1);
}
else
{
if (changedItems == null)
throw new ArgumentNullException("changedItems");
if (startingIndex < -1)
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "startingIndex");
InitializeAddOrRemove(action, changedItems, startingIndex);
}
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
/// </summary>
/// <param name="action">Can only be a Replace action.</param>
/// <param name="newItem">The new item replacing the original item.</param>
/// <param name="oldItem">The original item that is replaced.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
{
if (action != NotifyCollectionChangedAction.Replace)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, -1, -1);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
/// </summary>
/// <param name="action">Can only be a Replace action.</param>
/// <param name="newItem">The new item replacing the original item.</param>
/// <param name="oldItem">The original item that is replaced.</param>
/// <param name="index">The index of the item being replaced.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
{
if (action != NotifyCollectionChangedAction.Replace)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
int oldStartingIndex = index;
#if FEATURE_LEGACYNETCF
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
// Dev11 444113 quirk:
// This is a "Replace" so the old and new index should both be set to the index passed in however
// NetCF on Mango incorrectly leaves OldStartingIndex at -1 and Mango apps depend on this behavior.
oldStartingIndex = -1;
}
#endif
InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, index, oldStartingIndex);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
/// </summary>
/// <param name="action">Can only be a Replace action.</param>
/// <param name="newItems">The new items replacing the original items.</param>
/// <param name="oldItems">The original items that are replaced.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
{
if (action != NotifyCollectionChangedAction.Replace)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
if (newItems == null)
throw new ArgumentNullException("newItems");
if (oldItems == null)
throw new ArgumentNullException("oldItems");
InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
/// </summary>
/// <param name="action">Can only be a Replace action.</param>
/// <param name="newItems">The new items replacing the original items.</param>
/// <param name="oldItems">The original items that are replaced.</param>
/// <param name="startingIndex">The starting index of the items being replaced.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
{
if (action != NotifyCollectionChangedAction.Replace)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
if (newItems == null)
throw new ArgumentNullException("newItems");
if (oldItems == null)
throw new ArgumentNullException("oldItems");
InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Move event.
/// </summary>
/// <param name="action">Can only be a Move action.</param>
/// <param name="changedItem">The item affected by the change.</param>
/// <param name="index">The new index for the changed item.</param>
/// <param name="oldIndex">The old index for the changed item.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
{
if (action != NotifyCollectionChangedAction.Move)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
if (index < 0)
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
object[] changedItems= new object[] {changedItem};
InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Move event.
/// </summary>
/// <param name="action">The action that caused the event.</param>
/// <param name="changedItems">The items affected by the change.</param>
/// <param name="index">The new index for the changed items.</param>
/// <param name="oldIndex">The old index for the changed items.</param>
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
{
if (action != NotifyCollectionChangedAction.Move)
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
if (index < 0)
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
}
/// <summary>
/// Construct a NotifyCollectionChangedEventArgs with given fields (no validation). Used by WinRT marshaling.
/// </summary>
internal NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex)
{
_action = action;
#if FEATURE_LEGACYNETCF
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
_newItems = newItems;
}
else
#endif
{
_newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
}
_oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
_newStartingIndex = newIndex;
_oldStartingIndex = oldIndex;
}
private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
{
if (action == NotifyCollectionChangedAction.Add)
InitializeAdd(action, changedItems, startingIndex);
else if (action == NotifyCollectionChangedAction.Remove)
InitializeRemove(action, changedItems, startingIndex);
else
Contract.Assert(false, String.Format("Unsupported action: {0}", action.ToString()));
}
private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
{
_action = action;
#if FEATURE_LEGACYNETCF
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
_newItems = newItems;
}
else
#endif // !FEATURE_LEGACYNETCF
{
_newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
}
_newStartingIndex = newStartingIndex;
}
private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
{
_action = action;
_oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
_oldStartingIndex= oldStartingIndex;
}
private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
{
InitializeAdd(action, newItems, startingIndex);
InitializeRemove(action, oldItems, oldStartingIndex);
}
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
/// <summary>
/// The action that caused the event.
/// </summary>
public NotifyCollectionChangedAction Action
{
get { return _action; }
}
/// <summary>
/// The items affected by the change.
/// </summary>
public IList NewItems
{
get { return _newItems; }
}
/// <summary>
/// The old items affected by the change (for Replace events).
/// </summary>
public IList OldItems
{
get { return _oldItems; }
}
/// <summary>
/// The index where the change occurred.
/// </summary>
public int NewStartingIndex
{
get { return _newStartingIndex; }
}
/// <summary>
/// The old index where the change occurred (for Move events).
/// </summary>
public int OldStartingIndex
{
get { return _oldStartingIndex; }
}
//------------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
private NotifyCollectionChangedAction _action;
private IList _newItems, _oldItems;
private int _newStartingIndex = -1;
private int _oldStartingIndex = -1;
}
/// <summary>
/// The delegate to use for handlers that receive the CollectionChanged event.
/// </summary>
#if !MOBILE
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
#endif
public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);
}

View File

@@ -0,0 +1,246 @@
//------------------------------------------------------------------------------
// <copyright file="StringCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Collections.Specialized {
using System.Diagnostics;
using System.Collections;
/// <devdoc>
/// <para>Represents a collection of strings.</para>
/// </devdoc>
[
Serializable,
]
public class StringCollection : IList {
private ArrayList data = new ArrayList();
/// <devdoc>
/// <para>Represents the entry at the specified index of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
/// </devdoc>
public string this[int index] {
get {
return ((string)data[index]);
}
set {
data[index] = value;
}
}
/// <devdoc>
/// <para>Gets the number of strings in the
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public int Count {
get {
return data.Count;
}
}
bool IList.IsReadOnly
{
get
{
return false;
}
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
/// <devdoc>
/// <para>Adds a string with the specified value to the
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public int Add(string value) {
return data.Add(value);
}
/// <devdoc>
/// <para>Copies the elements of a string array to the end of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
/// </devdoc>
public void AddRange(string[] value) {
if (value == null) {
throw new ArgumentNullException("value");
}
data.AddRange(value);
}
/// <devdoc>
/// <para>Removes all the strings from the
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public void Clear() {
data.Clear();
}
/// <devdoc>
/// <para>Gets a value indicating whether the
/// <see cref='System.Collections.Specialized.StringCollection'/> contains a string with the specified
/// value.</para>
/// </devdoc>
public bool Contains(string value) {
return data.Contains(value);
}
/// <devdoc>
/// <para>Copies the <see cref='System.Collections.Specialized.StringCollection'/> values to a one-dimensional <see cref='System.Array'/> instance at the
/// specified index.</para>
/// </devdoc>
public void CopyTo(string[] array, int index) {
data.CopyTo(array, index);
}
/// <devdoc>
/// <para>Returns an enumerator that can iterate through
/// the <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public StringEnumerator GetEnumerator() {
return new StringEnumerator(this);
}
/// <devdoc>
/// <para>Returns the index of the first occurrence of a string in
/// the <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public int IndexOf(string value) {
return data.IndexOf(value);
}
/// <devdoc>
/// <para>Inserts a string into the <see cref='System.Collections.Specialized.StringCollection'/> at the specified
/// index.</para>
/// </devdoc>
public void Insert(int index, string value) {
data.Insert(index, value);
}
/// <devdoc>
/// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.StringCollection'/> is read-only.</para>
/// </devdoc>
public bool IsReadOnly {
get {
return false;
}
}
/// <devdoc>
/// <para>Gets a value indicating whether access to the
/// <see cref='System.Collections.Specialized.StringCollection'/>
/// is synchronized (thread-safe).</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/// <devdoc>
/// <para> Removes a specific string from the
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
/// </devdoc>
public void Remove(string value) {
data.Remove(value);
}
/// <devdoc>
/// <para>Removes the string at the specified index of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
/// </devdoc>
public void RemoveAt(int index) {
data.RemoveAt(index);
}
/// <devdoc>
/// <para>Gets an object that can be used to synchronize access to the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
/// </devdoc>
public object SyncRoot {
get {
return data.SyncRoot;
}
}
object IList.this[int index] {
get {
return this[index];
}
set {
this[index] = (string)value;
}
}
int IList.Add(object value) {
return Add((string)value);
}
bool IList.Contains(object value) {
return Contains((string) value);
}
int IList.IndexOf(object value) {
return IndexOf((string)value);
}
void IList.Insert(int index, object value) {
Insert(index, (string)value);
}
void IList.Remove(object value) {
Remove((string)value);
}
void ICollection.CopyTo(Array array, int index) {
data.CopyTo(array, index);
}
IEnumerator IEnumerable.GetEnumerator() {
return data.GetEnumerator();
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class StringEnumerator {
private System.Collections.IEnumerator baseEnumerator;
private System.Collections.IEnumerable temp;
internal StringEnumerator(StringCollection mappings) {
this.temp = (IEnumerable)(mappings);
this.baseEnumerator = temp.GetEnumerator();
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public string Current {
get {
return (string)(baseEnumerator.Current);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool MoveNext() {
return baseEnumerator.MoveNext();
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Reset() {
baseEnumerator.Reset();
}
}
}

View File

@@ -0,0 +1,458 @@
//------------------------------------------------------------------------------
// <copyright file="StringDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
*/
namespace System.Collections.Specialized {
using System.Runtime.InteropServices;
using System.Diagnostics;
using System;
using System.Collections;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Collections.Generic;
/// <devdoc>
/// <para>Implements a hashtable with the key strongly typed to be
/// a string rather than an object. </para>
/// <para>Consider this class obsolete - use Dictionary&lt;String, String&gt; instead
/// with a proper StringComparer instance.</para>
/// </devdoc>
[Serializable]
[DesignerSerializer("System.Diagnostics.Design.StringDictionaryCodeDomSerializer, " + AssemblyRef.SystemDesign, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + AssemblyRef.SystemDesign)]
// @
public class StringDictionary : IEnumerable {
// For compatibility, we want the Keys property to return values in lower-case.
// That means using ToLower in each property on this type. Also for backwards
// compatibility, we will be converting strings to lower-case, which has a
// problem for some Georgian alphabets. Can't really fix it now though...
internal Hashtable contents = new Hashtable();
/// <devdoc>
/// <para>Initializes a new instance of the StringDictionary class.</para>
/// <para>If you're using file names, registry keys, etc, you want to use
/// a Dictionary&lt;String, Object&gt; and use
/// StringComparer.OrdinalIgnoreCase.</para>
/// </devdoc>
public StringDictionary() {
}
/// <devdoc>
/// <para>Gets the number of key-and-value pairs in the StringDictionary.</para>
/// </devdoc>
public virtual int Count {
get {
return contents.Count;
}
}
/// <devdoc>
/// <para>Indicates whether access to the StringDictionary is synchronized (thread-safe). This property is
/// read-only.</para>
/// </devdoc>
public virtual bool IsSynchronized {
get {
return contents.IsSynchronized;
}
}
/// <devdoc>
/// <para>Gets or sets the value associated with the specified key.</para>
/// </devdoc>
public virtual string this[string key] {
get {
if( key == null ) {
throw new ArgumentNullException("key");
}
return (string) contents[key.ToLower(CultureInfo.InvariantCulture)];
}
set {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents[key.ToLower(CultureInfo.InvariantCulture)] = value;
}
}
/// <devdoc>
/// <para>Gets a collection of keys in the StringDictionary.</para>
/// </devdoc>
public virtual ICollection Keys {
get {
return contents.Keys;
}
}
/// <devdoc>
/// <para>Gets an object that can be used to synchronize access to the StringDictionary.</para>
/// </devdoc>
public virtual object SyncRoot {
get {
return contents.SyncRoot;
}
}
/// <devdoc>
/// <para>Gets a collection of values in the StringDictionary.</para>
/// </devdoc>
public virtual ICollection Values {
get {
return contents.Values;
}
}
/// <devdoc>
/// <para>Adds an entry with the specified key and value into the StringDictionary.</para>
/// </devdoc>
public virtual void Add(string key, string value) {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents.Add(key.ToLower(CultureInfo.InvariantCulture), value);
}
/// <devdoc>
/// <para>Removes all entries from the StringDictionary.</para>
/// </devdoc>
public virtual void Clear() {
contents.Clear();
}
/// <devdoc>
/// <para>Determines if the string dictionary contains a specific key</para>
/// </devdoc>
public virtual bool ContainsKey(string key) {
if( key == null ) {
throw new ArgumentNullException("key");
}
return contents.ContainsKey(key.ToLower(CultureInfo.InvariantCulture));
}
/// <devdoc>
/// <para>Determines if the StringDictionary contains a specific value.</para>
/// </devdoc>
public virtual bool ContainsValue(string value) {
return contents.ContainsValue(value);
}
/// <devdoc>
/// <para>Copies the string dictionary values to a one-dimensional <see cref='System.Array'/> instance at the
/// specified index.</para>
/// </devdoc>
public virtual void CopyTo(Array array, int index) {
contents.CopyTo(array, index);
}
/// <devdoc>
/// <para>Returns an enumerator that can iterate through the string dictionary.</para>
/// </devdoc>
public virtual IEnumerator GetEnumerator() {
return contents.GetEnumerator();
}
/// <devdoc>
/// <para>Removes the entry with the specified key from the string dictionary.</para>
/// </devdoc>
public virtual void Remove(string key) {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents.Remove(key.ToLower(CultureInfo.InvariantCulture));
}
/// <summary>
/// Make this StringDictionary subservient to some other collection.
/// <para>Some code was replacing the contents field with a Hashtable created elsewhere.
/// While it may not have been incorrect, we don't want to encourage that pattern, because
/// it will replace the IEqualityComparer in the Hashtable, and creates a possibly-undesirable
/// link between two seemingly different collections. Let's discourage that somewhat by
/// making this an explicit method call instead of an internal field assignment.</para>
/// </summary>
/// <param name="useThisHashtableInstead">Replaces the backing store with another, possibly aliased Hashtable.</param>
internal void ReplaceHashtable(Hashtable useThisHashtableInstead) {
contents = useThisHashtableInstead;
}
internal IDictionary<string, string> AsGenericDictionary() {
return new GenericAdapter(this);
}
#region GenericAdapter
//
// This class is used to make StringDictionary implement IDictionary<string,string> indirectly.
// This is done to prevent StringDictionary be serialized as IDictionary<string,string> and break its serialization by DataContractSerializer due to a bug in the serialization code.
private class GenericAdapter : IDictionary<string, string>
{
StringDictionary m_stringDictionary;
internal GenericAdapter(StringDictionary stringDictionary) {
m_stringDictionary = stringDictionary;
}
#region IDictionary<string, string> Members
public void Add(string key, string value) {
// GenericAdapter.Add has the semantics of Item property to make ProcessStartInfo.Environment deserializable by DataContractSerializer.
// ProcessStartInfo.Environment property does not have a setter
// and so during deserialization the serializer initializes the property by calling get_Environment and
// then populates it via IDictionary<,>.Add per item.
// However since get_Environment gives the current snapshot of environment variables we might try to insert a key that already exists.
// (For Example 'PATH') causing an exception. This implementation ensures that we overwrite values in case of duplication.
this[key] = value;
}
public bool ContainsKey(string key) {
return m_stringDictionary.ContainsKey(key);
}
public void Clear() {
m_stringDictionary.Clear();
}
public int Count {
get {
return m_stringDictionary.Count;
}
}
// Items added to allow StringDictionary to provide IDictionary<string, string> support.
ICollectionToGenericCollectionAdapter _values;
ICollectionToGenericCollectionAdapter _keys;
// IDictionary<string,string>.Item vs StringDictioanry.Item
// IDictionary<string,string>.get_Item i. KeyNotFoundException when the property is retrieved and key is not found.
// StringBuilder.get_Item i. Returns null in case the key is not found.
public string this[string key] {
get {
if (key == null) {
throw new ArgumentNullException("key");
}
if (!m_stringDictionary.ContainsKey(key)) throw new KeyNotFoundException();
return m_stringDictionary[key];
}
set {
if (key == null) {
throw new ArgumentNullException("key");
}
m_stringDictionary[key] = value;
}
}
// This method returns a read-only view of the Keys in the StringDictinary.
public ICollection<string> Keys {
get {
if( _keys == null ) {
_keys = new ICollectionToGenericCollectionAdapter(m_stringDictionary, KeyOrValue.Key);
}
return _keys;
}
}
// This method returns a read-only view of the Values in the StringDictionary.
public ICollection<string> Values {
get {
if( _values == null ) {
_values = new ICollectionToGenericCollectionAdapter(m_stringDictionary, KeyOrValue.Value);
}
return _values;
}
}
// IDictionary<string,string>.Remove vs StringDictionary.Remove.
// IDictionary<string,string>.Remove- i. Returns a bool status that represents success\failure.
// ii. Returns false in case key is not found.
// StringDictionary.Remove i. Does not return the status and does nothing in case key is not found.
public bool Remove(string key) {
// Check if the key is not present and return false.
if (!m_stringDictionary.ContainsKey(key)) return false;
// We call the virtual StringDictionary.Remove method to ensure any subClass gets the expected behavior.
m_stringDictionary.Remove(key);
// If the above call has succeeded we simply return true.
return true;
}
public bool TryGetValue(string key, out string value) {
if (!m_stringDictionary.ContainsKey(key)) {
value = null;
return false;
}
value = m_stringDictionary[key];
return true;
}
void ICollection<KeyValuePair<string, string>>.Add(KeyValuePair<string, string> item) {
m_stringDictionary.Add(item.Key, item.Value);
}
bool ICollection<KeyValuePair<string, string>>.Contains(KeyValuePair<string, string> item) {
string value;
return TryGetValue(item.Key, out value) && value.Equals(item.Value);
}
void ICollection<KeyValuePair<string, string>>.CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) {
if( array == null )
throw new ArgumentNullException("array", SR.GetString(SR.ArgumentNull_Array));
if( arrayIndex < 0 )
throw new ArgumentOutOfRangeException("arrayIndex", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
if( array.Length - arrayIndex < Count )
throw new ArgumentException(SR.GetString(SR.Arg_ArrayPlusOffTooSmall));
int index = arrayIndex;
foreach (DictionaryEntry entry in m_stringDictionary) {
array[index++] = new KeyValuePair<string, string>((string)entry.Key, (string)entry.Value);
}
}
bool ICollection<KeyValuePair<string,string>>.IsReadOnly {
get {
return false;
}
}
// ICollection<KeyValuePair<string, string>>.Remove vs StringDictionary.Remove
// ICollection<KeyValuePair<string, string>>.Remove - i. Return status.
// ii. Returns false in case the items is not found.
// StringDictionary.Remove i. Does not return a status and does nothing in case the key is not found.
bool ICollection<KeyValuePair<string, string>>.Remove(KeyValuePair<string, string> item) {
// If the item is not found return false.
ICollection<KeyValuePair<string, string>> iCollection = this;
if( !iCollection.Contains(item) ) return false;
// We call the virtual StringDictionary.Remove method to ensure any subClass gets the expected behavior.
m_stringDictionary.Remove(item.Key);
// If the above call has succeeded we simply return true.
return true;
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
// The implementation asummes that this.GetEnumerator().Current can be casted to DictionaryEntry.
// and although StringDictionary.GetEnumerator() returns IEnumerator and is a virtual method
// it should be ok to take that assumption since it is an implicit contract.
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
foreach (DictionaryEntry dictionaryEntry in m_stringDictionary)
yield return new KeyValuePair<string, string>((string)dictionaryEntry.Key, (string)dictionaryEntry.Value);
}
internal enum KeyOrValue // Used internally for IDictionary<string, string> support
{
Key,
Value
}
// This Adapter converts StringDictionary.Keys and StringDictionary.Values to ICollection<string>
// Since StringDictionary implements a virtual StringDictionary.Keys and StringDictionary.Values
private class ICollectionToGenericCollectionAdapter : ICollection<string> {
StringDictionary _internal;
KeyOrValue _keyOrValue;
public ICollectionToGenericCollectionAdapter(StringDictionary source, KeyOrValue keyOrValue) {
if (source == null) throw new ArgumentNullException("source");
_internal = source;
_keyOrValue = keyOrValue;
}
public void Add(string item) {
ThrowNotSupportedException();
}
public void Clear() {
ThrowNotSupportedException();
}
public void ThrowNotSupportedException() {
if( _keyOrValue == KeyOrValue.Key ) {
throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyCollectionSet)); //Same as KeyCollection/ValueCollection
}
throw new NotSupportedException(SR.GetString(SR.NotSupported_ValueCollectionSet)); //Same as KeyCollection/ValueCollection
}
public bool Contains(string item) {
// The underlying backing store for the StringDictionary is a HashTable so we
// want to delegate Contains to respective ContainsKey/ContainsValue functionality
// depending upon whether we are using Keys or Value collections.
if( _keyOrValue == KeyOrValue.Key ) {
return _internal.ContainsKey(item);
}
return _internal.ContainsValue(item);
}
public void CopyTo(string[] array, int arrayIndex) {
var collection = GetUnderlyingCollection();
collection.CopyTo(array, arrayIndex);
}
public int Count {
get {
return _internal.Count; // hashtable count is same as key/value count.
}
}
public bool IsReadOnly {
get {
return true; //Same as KeyCollection/ValueCollection
}
}
public bool Remove(string item) {
ThrowNotSupportedException();
return false;
}
private ICollection GetUnderlyingCollection() {
if( _keyOrValue == KeyOrValue.Key ) {
return (ICollection) _internal.Keys;
}
return (ICollection) _internal.Values;
}
public IEnumerator<string> GetEnumerator() {
ICollection collection = GetUnderlyingCollection();
// This is doing the same as collection.Cast<string>()
foreach (string entry in collection) {
yield return entry;
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetUnderlyingCollection().GetEnumerator();
}
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <copyright file="StringDictionaryWithComparer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// StringDictionary compares keys by converting them to lowercase first, using the Invariant culture.
// This is not the right thing to do for file names, registry keys, environment variable etc.
// This internal version of StringDictionary accepts an IEqualityComparer and enables you to
// customize the string comparison to be StringComparer.OrdinalIgnoreCase for the above cases.
namespace System.Collections.Specialized {
using System.Runtime.InteropServices;
using System.Diagnostics;
using System;
using System.Collections;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
[Serializable]
internal class StringDictionaryWithComparer : StringDictionary {
public StringDictionaryWithComparer() : this(StringComparer.OrdinalIgnoreCase) {
}
public StringDictionaryWithComparer(IEqualityComparer comparer) {
ReplaceHashtable(new Hashtable(comparer));
}
public override string this[string key] {
get {
if( key == null ) {
throw new ArgumentNullException("key");
}
return (string) contents[key];
}
set {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents[key] = value;
}
}
public override void Add(string key, string value) {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents.Add(key, value);
}
public override bool ContainsKey(string key) {
if( key == null ) {
throw new ArgumentNullException("key");
}
return contents.ContainsKey(key);
}
public override void Remove(string key) {
if( key == null ) {
throw new ArgumentNullException("key");
}
contents.Remove(key);
}
}
}