summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Security/Policy/Evidence.cs
blob: 8bf8aa7e9222475d0607f116158181b6daa0e90a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// 

namespace System.Security.Policy
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration.Assemblies;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
#if FEATURE_SERIALIZATION
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
#endif // FEATURE_SERIALIZATION
    using System.Security.Permissions;
    using System.Security.Util;
    using System.Threading;
    using Microsoft.Win32.SafeHandles;

    /// <summary>
    ///     The Evidence class keeps track of information that can be used to make security decisions about
    ///     an assembly or an AppDomain.  There are two types of evidence, one is supplied by the CLR or a
    ///     host, the other supplied by the assembly itself.
    ///     
    ///     We keep a dictionary that maps each type of possbile evidence to an EvidenceTypeDescriptor which
    ///     contains the evidence objects themselves if they exist as well as some extra metadata about that
    ///     type of evidence.  This dictionary is fully populated with keys for host evidence at all times and
    ///     for assembly evidence the first time the application evidence is touched.  This means that if a
    ///     Type key does not exist in the dictionary, then that particular type of evidence will never be
    ///     given to the assembly or AppDomain in question as host evidence.  The only exception is if the
    ///     user later manually adds host evidence via the AddHostEvidence API.
    ///     
    ///     Assembly supplied evidence is created up front, however host supplied evidence may be lazily
    ///     created.  In the lazy creation case, the Type will map to either an EvidenceTypeDescriptor that does
    ///     not contain any evidence data or null.  As requests come in for that evidence, we'll populate the
    ///     EvidenceTypeDescriptor appropriately.
    /// </summary>
#if FEATURE_SERIALIZATION
    [Serializable]
#endif
    [ComVisible(true)]
    public sealed class Evidence
#if FEATURE_CAS_POLICY
 : ICollection
#endif // FEATURE_CAS_POLICY
    {
#if !FEATURE_CORECLR && FEATURE_RWLOCK
#if FEATURE_SERIALIZATION
        [OptionalField(VersionAdded = 4)]
        private Dictionary<Type, EvidenceTypeDescriptor> m_evidence;

        [OptionalField(VersionAdded = 4)]
        private bool m_deserializedTargetEvidence;

        // These fields are only used to deserialize v2.0 serialized versions of Evidence. It will be null
        // after the seriailzation process is complete, and should not be used.
#pragma warning disable 414
        private volatile ArrayList m_hostList;
        private volatile ArrayList m_assemblyList;
#pragma warning restore 414
#else // !FEATURE_SERIALIZATION
        private Dictionary<Type, EvidenceTypeDescriptor> m_evidence;
#endif // FEATURE_SERIALIZATION

        [NonSerialized]
        private ReaderWriterLock m_evidenceLock;

        [NonSerialized]
        private uint m_version;

        [NonSerialized]
        private IRuntimeEvidenceFactory m_target;

        private bool m_locked;

        // If this evidence collection is a clone where we may need to backpatch to the original, this will
        // reference the collection it was cloned from.  See
        // code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence 
        [NonSerialized]
        private WeakReference m_cloneOrigin;

        private static volatile Type[] s_runtimeEvidenceTypes;

        /// <summary>
        ///     Set of actions that we could perform if we detect that we are attempting to add evidence
        ///     when we already have evidence of that type stored.
        /// </summary>
        private enum DuplicateEvidenceAction
        {
            Throw,                  // Throw an exception
            Merge,                  // Create a list of all the evidence objects
            SelectNewObject         // The newly added object wins
        }

#if FEATURE_CAS_POLICY
        public Evidence()
        {
            m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
            m_evidenceLock = new ReaderWriterLock();
        }
#endif // FEATURE_CAS_POLICY

        /// <summary>
        ///     Create a deep copy of an evidence object
        /// </summary>
        public Evidence(Evidence evidence)
        {
            m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();

            if (evidence != null)
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(evidence, EvidenceLockHolder.LockType.Reader))
                {
                    foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in evidence.m_evidence)
                    {
                        EvidenceTypeDescriptor cloneDescriptor = evidenceType.Value;
                        if (cloneDescriptor != null)
                        {
                            cloneDescriptor = cloneDescriptor.Clone();
                        }

                        m_evidence[evidenceType.Key] = cloneDescriptor;
                    }

                    m_target = evidence.m_target;
                    m_locked = evidence.m_locked;
#if FEATURE_SERIALIZATION
                    m_deserializedTargetEvidence = evidence.m_deserializedTargetEvidence;
#endif // FEATURE_SERIALIZATION

                    // see code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence
                    if (evidence.Target != null)
                    {
                        m_cloneOrigin = new WeakReference(evidence);
                    }
                }
            }

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }

        [Obsolete("This constructor is obsolete. Please use the constructor which takes arrays of EvidenceBase instead.")]
        public Evidence(object[] hostEvidence, object[] assemblyEvidence)
        {
            m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();

            // This is a legacy evidence entry point, so we add through the legacy add APIs in order to get
            // proper legacy wrapping and merge behavior.
#pragma warning disable 618
            if (hostEvidence != null)
            {
                foreach (object hostEvidenceObject in hostEvidence)
                {
                    AddHost(hostEvidenceObject);
                }
            }

            if (assemblyEvidence != null)
            {
                foreach (object assemblyEvidenceObject in assemblyEvidence)
                {
                    AddAssembly(assemblyEvidenceObject);
                }
            }
#pragma warning restore 618

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }

        public Evidence(EvidenceBase[] hostEvidence, EvidenceBase[] assemblyEvidence)
        {
            m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();

            if (hostEvidence != null)
            {
                foreach (EvidenceBase hostEvidenceObject in hostEvidence)
                {
                    AddHostEvidence(hostEvidenceObject, GetEvidenceIndexType(hostEvidenceObject), DuplicateEvidenceAction.Throw);
                }
            }

            if (assemblyEvidence != null)
            {
                foreach (EvidenceBase assemblyEvidenceObject in assemblyEvidence)
                {
                    AddAssemblyEvidence(assemblyEvidenceObject, GetEvidenceIndexType(assemblyEvidenceObject), DuplicateEvidenceAction.Throw);
                }
            }

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }

        /// <summary>
        ///     Create an empty evidence collection which will contain evidence for a specific assembly or
        ///     AppDomain
        /// </summary>
        [SecuritySafeCritical]
        internal Evidence(IRuntimeEvidenceFactory target)
        {
            Contract.Assert(target != null);

            m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
            m_target = target;

            // Setup the types of evidence that the CLR can generate for a target as keys in the dictionary
            foreach (Type runtimeEvidenceType in RuntimeEvidenceTypes)
            {
                BCLDebug.Assert(typeof(EvidenceBase).IsAssignableFrom(runtimeEvidenceType), "All runtime evidence types should be EvidenceBases");
                m_evidence[runtimeEvidenceType] = null;
            }

            QueryHostForPossibleEvidenceTypes();

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }

        internal static Type[] RuntimeEvidenceTypes
        {
            get
            {
                if (s_runtimeEvidenceTypes == null)
                {
                    Type[] runtimeEvidenceTypes = new Type[]
                    {
#if FEATURE_CLICKONCE
                        typeof(System.Runtime.Hosting.ActivationArguments),
#endif // FEATURE_CLICKONCE
#if FEATURE_CAS_POLICY
                        typeof(ApplicationDirectory),
#endif // FEATURE_CAS_POLICY
                        typeof(ApplicationTrust),
#if FEATURE_CAS_POLICY
                        typeof(GacInstalled),
                        typeof(Hash),
                        typeof(Publisher),
#endif // FEATURE_CAS_POLICY
                        typeof(Site),
                        typeof(StrongName),
                        typeof(Url),
                        typeof(Zone)
                    };

#if FEATURE_CAS_POLICY
                    // We only supply permission request evidence in legacy CAS mode
                    if (AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
                    {
#pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
                        int l = runtimeEvidenceTypes.Length;
                        Array.Resize(ref runtimeEvidenceTypes, l+1);
                        runtimeEvidenceTypes[l] = typeof(PermissionRequestEvidence);
#pragma warning restore 618
                    }
#endif // FEATURE_CAS_POLICY

                    s_runtimeEvidenceTypes = runtimeEvidenceTypes;
                }

                return s_runtimeEvidenceTypes;
            }
        }

        //
        // #EvidenceLock
        // 
        // Evidence synchronization locking wrappers. In the case where the lock has not yet been created,
        // we know that we're in the process of constructing the evidence collection and therefore we can
        // act as though the evidence is locked.  If there is a lock in place, then just delegate back to it.
        //
        // The nested EvidenceLockHolder and EvidenceUpgradeLockHolder utility classes can be used to wrap
        // these methods when acquiring and releasing the evidence lock.
        //

        // Millisecond timeout when waiting to acquire the evidence lock
        private const int LockTimeout = 5000;

        private bool IsReaderLockHeld
        {
            get { return m_evidenceLock == null || m_evidenceLock.IsReaderLockHeld; }
        }

        private bool IsWriterLockHeld
        {
            get { return m_evidenceLock == null || m_evidenceLock.IsWriterLockHeld; }
        }

        private void AcquireReaderLock()
        {
            Contract.Assert(m_evidenceLock == null || !IsReaderLockHeld);

            if (m_evidenceLock != null)
            {
                m_evidenceLock.AcquireReaderLock(LockTimeout);
            }
        }

        private void AcquireWriterlock()
        {
            Contract.Assert(m_evidenceLock == null || !IsWriterLockHeld);

            if (m_evidenceLock != null)
            {
                m_evidenceLock.AcquireWriterLock(LockTimeout);
            }
        }

        private void DowngradeFromWriterLock(ref LockCookie lockCookie)
        {
            Contract.Assert(IsWriterLockHeld);
            if (m_evidenceLock != null)
            {
                m_evidenceLock.DowngradeFromWriterLock(ref lockCookie);
            }
        }

        private LockCookie UpgradeToWriterLock()
        {
            Contract.Assert(IsReaderLockHeld);
            return m_evidenceLock != null ? m_evidenceLock.UpgradeToWriterLock(LockTimeout) : new LockCookie();
        }

        private void ReleaseReaderLock()
        {
            Contract.Assert(IsReaderLockHeld);

            if (m_evidenceLock != null)
            {
                m_evidenceLock.ReleaseReaderLock();
            }
        }

        private void ReleaseWriterLock()
        {
            Contract.Assert(IsWriterLockHeld);

            if (m_evidenceLock != null)
            {
                m_evidenceLock.ReleaseWriterLock();
            }
        }

        [Obsolete("This method is obsolete. Please use AddHostEvidence instead.")]
        [SecuritySafeCritical]
        public void AddHost(object id)
        {
            if (id == null)
                throw new ArgumentNullException("id");
            if (!id.GetType().IsSerializable)
                throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
            Contract.EndContractBlock();

            if (m_locked)
            {
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
            }

            EvidenceBase evidence = WrapLegacyEvidence(id);
            Type evidenceIndex = GetEvidenceIndexType(evidence);

            // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey
            // APIs, then allow the evidences to merge together.
            AddHostEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge);
        }

        [Obsolete("This method is obsolete. Please use AddAssemblyEvidence instead.")]
        public void AddAssembly(object id)
        {
            if (id == null)
                throw new ArgumentNullException("id");
            if (!id.GetType().IsSerializable)
                throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
            Contract.EndContractBlock();

            EvidenceBase evidence = WrapLegacyEvidence(id);
            Type evidenceIndex = GetEvidenceIndexType(evidence);

            // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey
            // APIs, then allow the evidences to merge together.
            AddAssemblyEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge);
        }

        /// <summary>
        ///     Add a piece of evidence to the assembly supplied evidence list. This method will disallow adding
        ///     evidence if there is already evidence of that type in the assembly list.
        /// </summary>
        [ComVisible(false)]
        public void AddAssemblyEvidence<T>(T evidence) where T : EvidenceBase
        {
            if (evidence == null)
                throw new ArgumentNullException("evidence");
            Contract.EndContractBlock();

            // Index the evidence under the type that the Add function was called with, unless we were given
            // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a
            // more specific type.
            Type evidenceType = typeof(T);
            if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter)
            {
                evidenceType = GetEvidenceIndexType(evidence);
            }

            AddAssemblyEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
        }

        private void AddAssemblyEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                AddAssemblyEvidenceNoLock(evidence, evidenceType, duplicateAction);
            }
        }

        private void AddAssemblyEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        {
            Contract.Assert(IsWriterLockHeld);
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null);

            // We need to make sure that any target supplied evidence is deserialized before adding to the
            // Assembly collection in order to preserve the semantics that the evidence objects supplied by
            // the target are the original versions and evidence objects added via the APIs are the duplicates.
            DeserializeTargetEvidence();

            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);

            ++m_version;
            if (descriptor.AssemblyEvidence == null)
            {
                descriptor.AssemblyEvidence = evidence;
            }
            else
            {
                descriptor.AssemblyEvidence = HandleDuplicateEvidence(descriptor.AssemblyEvidence,
                                                                      evidence,
                                                                      duplicateAction);
            }
        }

        /// <summary>
        ///     Add a piece of evidence to the host supplied evidence list. This method will disallow adding
        ///     evidence if there is already evidence of that type in the host list.
        /// </summary>
        [ComVisible(false)]
        public void AddHostEvidence<T>(T evidence) where T : EvidenceBase
        {
            if (evidence == null)
                throw new ArgumentNullException("evidence");
            Contract.EndContractBlock();

            // Index the evidence under the type that the Add function was called with, unless we were given
            // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a
            // more specific type.
            Type evidenceType = typeof(T);
            if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter)
            {
                evidenceType = GetEvidenceIndexType(evidence);
            }

            AddHostEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
        }

        [SecuritySafeCritical]
        private void AddHostEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        {
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null);

            if (Locked)
            {
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                AddHostEvidenceNoLock(evidence, evidenceType, duplicateAction);
            }
        }

        /// <summary>
        ///     Add evidence to the host supplied evidence collection without acquiring the evidence lock or
        ///     checking to make sure that the caller has permission to bypass locked evidence.
        /// </summary>
        private void AddHostEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        {
            Contract.Assert(IsWriterLockHeld);
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null);

            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);

            ++m_version;
            if (descriptor.HostEvidence == null)
            {
                descriptor.HostEvidence = evidence;
            }
            else
            {
                descriptor.HostEvidence = HandleDuplicateEvidence(descriptor.HostEvidence,
                                                                  evidence,
                                                                  duplicateAction);
            }
        }

        /// <summary>
        ///     Ask the host for the types of evidence that it might provide if it is asked.
        ///     
        ///     This should only be called when setting up the Evidence collection to interact with the
        ///     host, and should not be used once that connection is established and the evidence has been
        ///     made available to user code.
        /// </summary>
        [SecurityCritical]
        private void QueryHostForPossibleEvidenceTypes()
        {
#if FEATURE_CAS_POLICY
            Contract.Assert(IsWriterLockHeld);

            // First check to see if we have a HostSecurityManager
            if (AppDomain.CurrentDomain.DomainManager != null)
            {
                HostSecurityManager hsm = AppDomain.CurrentDomain.DomainManager.HostSecurityManager;
                if (hsm != null)
                {
                    Type[] hostSuppliedTypes = null;

                    AppDomain targetDomain = m_target.Target as AppDomain;
                    Assembly targetAssembly = m_target.Target as Assembly;

                    //
                    // If the HostSecurityManager wants to supply evidence for the type of target that we have,
                    // then ask it what types of evidence it might supply.
                    //

                    if (targetAssembly != null &&
                        (hsm.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
                    {
                        hostSuppliedTypes = hsm.GetHostSuppliedAssemblyEvidenceTypes(targetAssembly);
                    }
                    else if (targetDomain != null &&
                             (hsm.Flags & HostSecurityManagerOptions.HostAppDomainEvidence) == HostSecurityManagerOptions.HostAppDomainEvidence)
                    {
                        hostSuppliedTypes = hsm.GetHostSuppliedAppDomainEvidenceTypes();
                    }

                    //
                    // Finally, mark the descriptor for each of the types that the host can supply to indicate
                    // we should ask the host to generate them if we're asked.
                    // 

                    if (hostSuppliedTypes != null)
                    {
                        foreach (Type hostEvidenceType in hostSuppliedTypes)
                        {
                            EvidenceTypeDescriptor evidenceDescriptor = GetEvidenceTypeDescriptor(hostEvidenceType, true);
                            evidenceDescriptor.HostCanGenerate = true;
                        }
                    }
                }
            }
#endif // FEATURE_CAS_POLICY
        }

        internal bool IsUnmodified
        {
            get { return m_version == 0; }
        }

        /// <summary>
        ///     Set or check to see if the evidence is locked.  Locked evidence cannot have its host supplied
        ///     evidence list be modified without a successful demand for ControlEvidence.  Any code can lock
        ///     evidence, but only code with ControlEvidence may unlock it.
        ///     
        ///     This lock is not the same as the synchronization lock that gates access to the evidence collection.
        /// </summary>
        public bool Locked
        {
            get
            {
                return m_locked;
            }

            [SecuritySafeCritical]
            set
            {
                if (!value)
                {
                    new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();

                    m_locked = false;
                }
                else
                {
                    m_locked = true;
                }
            }
        }

        /// <summary>
        ///     Target of any delay generated evidence objects
        /// </summary>
        internal IRuntimeEvidenceFactory Target
        {
            get { return m_target; }

            //
            // There are two retargeting scenarios supported:
            // 
            //   1. A PEFileEvidenceFactory is being upgraded to an AssemblyEvidenceFactory and we don't want
            //      to throw away any already generated evidence.
            //   2. A detached evidence collection is being applied to an AppDomain and that domain has a
            //      HostSecurityManager. In that case, we want to attach the target to the AppDomain to
            //      allow the HostSecurityManager to get callbacks for delay generated evidence.
            // 

            [SecurityCritical]
            set
            {
#if FEATURE_CAS_POLICY
                Contract.Assert((m_target != null && m_target is PEFileEvidenceFactory && value != null && value is AssemblyEvidenceFactory) ||
                                (m_target == null && value != null && value is AppDomainEvidenceFactory),
                                "Evidence retargeting should only be from PEFile -> Assembly or detached -> AppDomain.");
#endif // FEATURE_CAS_POLICY

                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
                {
                    m_target = value;

                    // Since we've updated what we're pointing at, we need to query the host to determine what
                    // types of evidence that it can generate for this new target.
                    QueryHostForPossibleEvidenceTypes();
                }
            }
        }

        /// <summary>
        ///     Get the type that would be used to index into the evidence dictionary for this object
        /// </summary>
        private static Type GetEvidenceIndexType(EvidenceBase evidence)
        {
            Contract.Assert(evidence != null);

            //
            // Legacy wrapper evidence types should be indexed via the type of evidence that they're wrapping
            // so check to see if we have one of those; otherwise just return the type itself.
            //

            ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
            return adapter == null ? evidence.GetType() : adapter.EvidenceType;
        }

        /// <summary>
        ///     Get the type descriptor for a specific type of evidence.  This method should be used instead
        ///     of accessing the dictionary directly as it will handle the case where a new descriptor needs
        ///     to be created.
        /// </summary>
        internal EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType)
        {
            return GetEvidenceTypeDescriptor(evidenceType, false);
        }

        /// <summary>
        ///     Get the type descriptor for a specific type of evidence, optionally creating a descriptor if
        ///     we did not yet know about this type of evidence.  This method should be used instead of
        ///     accessing the dictionary directly as it will handle the case where a new descriptor needs
        ///     to be created.
        /// </summary>
        private EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType, bool addIfNotExist)
        {
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(evidenceType != null);

            // If we don't know about the type being indexed and we don't want to add it then exit out
            EvidenceTypeDescriptor descriptor = null;
            if (!m_evidence.TryGetValue(evidenceType, out descriptor) && !addIfNotExist)
            {
                return null;
            }

            // If we haven't yet created a descriptor for this type then create one now
            if (descriptor == null)
            {
                descriptor = new EvidenceTypeDescriptor();
#if _DEBUG
                descriptor.SetEvidenceType(evidenceType);
#endif // _DEBUG

                bool upgradedLock = false;
                LockCookie upgradeCookie = new LockCookie();
                try
                {
                    if (!IsWriterLockHeld)
                    {
                        upgradeCookie = UpgradeToWriterLock();
                        upgradedLock = true;
                    }

                    m_evidence[evidenceType] = descriptor;
                }
                finally
                {
                    if (upgradedLock)
                        DowngradeFromWriterLock(ref upgradeCookie);
                }
            }

            return descriptor;
        }

        /// <summary>
        ///     This method is called if a piece of evidence is added but another piece of evidence of the same
        ///     type already existed.  We have different strategies depending on compatibility concerns of the
        ///     calling code.
        /// </summary>
        private static EvidenceBase HandleDuplicateEvidence(EvidenceBase original,
                                                            EvidenceBase duplicate,
                                                            DuplicateEvidenceAction action)
        {
            Contract.Assert(original != null);
            Contract.Assert(duplicate != null);
            Contract.Assert(original.GetType() == duplicate.GetType() || original.GetType() == typeof(LegacyEvidenceList));

            switch (action)
            {
                // Throw - duplicate evidence is not allowed (Arrowhead behavior), so throw an exception
                case DuplicateEvidenceAction.Throw:
                    throw new InvalidOperationException(Environment.GetResourceString("Policy_DuplicateEvidence", duplicate.GetType().FullName));

                // SelectNewObject - MergeWithNoDuplicates behavior - the duplicate object wins
                case DuplicateEvidenceAction.SelectNewObject:
                    return duplicate;

                // Merge - compat behavior. Merge the old and new evidence into a list so that both may exist
                case DuplicateEvidenceAction.Merge:

                    LegacyEvidenceList list = original as LegacyEvidenceList;
                    if (list == null)
                    {
                        list = new LegacyEvidenceList();
                        list.Add(original);
                    }

                    list.Add(duplicate);
                    return list;

                default:
                    BCLDebug.Assert(false, "Uknown DuplicateEvidenceAction");
                    return null;
            }
        }

        /// <summary>
        ///     Wrap evidence we recieved through a legacy API to ensure that it is stored in an EvidenceBase
        /// </summary>
        private static EvidenceBase WrapLegacyEvidence(object evidence)
        {
            Contract.Assert(evidence != null);

            EvidenceBase wrappedEvidence = evidence as EvidenceBase;
            if (wrappedEvidence == null)
            {
                wrappedEvidence = new LegacyEvidenceWrapper(evidence);
            }

            return wrappedEvidence;
        }

        /// <summary>
        ///     Upwrap evidence stored in a legacy adapter.
        ///     
        ///     This is only necessary for the case where multiple objects derived from EvidenceBase is
        ///     are added via the legacy APIs and are then retrieved via GetHostEvidence. This may occur if
        ///     a legacy application adds CLR supplied evidence types via the old APIs and a new application
        ///     consumes the resulting evidence.
        /// </summary>
        private static object UnwrapEvidence(EvidenceBase evidence)
        {
            ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
            return adapter == null ? evidence : adapter.EvidenceObject;
        }

        /// <summary>
        ///     Merge two evidence collections together.  Note that this will cause all of the lazily
        ///     generated evidence for the input collection to be generated, as well as causing any lazily
        ///     generated evidence that both collections share to be generated in the target.
        /// </summary>
        [SecuritySafeCritical]
        public void Merge(Evidence evidence)
        {
            if (evidence == null)
            {
                return;
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                bool checkedLock = false;
                IEnumerator hostEnumerator = evidence.GetHostEnumerator();
                while (hostEnumerator.MoveNext())
                {
                    if (Locked && !checkedLock)
                    {
                        new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
                        checkedLock = true;
                    }

                    // If we could potentially have evidence of the type about to be merged into our host list,
                    // then make sure that we generate that evidence before merging.  This will prevent the
                    // newly merged evidence from masking the value that we would have generated on our own.
                    Type hostEvidenceType = hostEnumerator.Current.GetType();
                    if (m_evidence.ContainsKey(hostEvidenceType))
                    {
                        GetHostEvidenceNoLock(hostEvidenceType);
                    }

                    EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
                    AddHostEvidenceNoLock(hostEvidence,
                                          GetEvidenceIndexType(hostEvidence),
                                          DuplicateEvidenceAction.Merge);
                }

                // Add each piece of assembly evidence. We don't need to deserialize our copy of the
                // evidence because AddAssemblyEvidenceNoLock will do this for us.
                IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
                while (assemblyEnumerator.MoveNext())
                {
                    EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
                    AddAssemblyEvidenceNoLock(assemblyEvidence,
                                              GetEvidenceIndexType(assemblyEvidence),
                                              DuplicateEvidenceAction.Merge);
                }
            }
        }

        /// <summary>
        ///     Same as merge, except only one instance of any one evidence type is allowed. When duplicates
        ///     are found, the evidence in the input argument will have priority. Note this will force the
        ///     entire input evidence to be generated, and does not check for locked evidence
        /// </summary>
        internal void MergeWithNoDuplicates(Evidence evidence)
        {
            if (evidence == null)
            {
                return;
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                IEnumerator hostEnumerator = evidence.GetHostEnumerator();
                while (hostEnumerator.MoveNext())
                {
                    EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
                    AddHostEvidenceNoLock(hostEvidence,
                                          GetEvidenceIndexType(hostEvidence),
                                          DuplicateEvidenceAction.SelectNewObject);
                }

                IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
                while (assemblyEnumerator.MoveNext())
                {
                    EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
                    AddAssemblyEvidenceNoLock(assemblyEvidence,
                                              GetEvidenceIndexType(assemblyEvidence),
                                              DuplicateEvidenceAction.SelectNewObject);
                }
            }
        }

#if FEATURE_SERIALIZATION
        /// <summary>
        ///     Do a full serialization of the evidence, which requires that we generate all of the evidence
        ///     we can and disconnect ourselves from the host and source assembly.
        /// </summary>
        [ComVisible(false)]
        [OnSerializing]
        [SecurityCritical]
        [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
        private void OnSerializing(StreamingContext context)
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                // First, force all of the host evidence that might be lazily generated to be created
                foreach (Type evidenceType in new List<Type>(m_evidence.Keys))
                {
                    GetHostEvidenceNoLock(evidenceType);
                }

                // Also ensure that all serialized assembly evidence has been created
                DeserializeTargetEvidence();
            }

            // Fill in legacy evidence lists. We can't guarantee thread-safety here using locks
            // because we can't put a lock in the serialization code that will read the lists.
            // The best we can do is prevent another thread from seeing a half-populated list.
            // Therefore, we assign the lists after we've populated them fully (and declare them volatile.)
            ArrayList hostList = new ArrayList();
            IEnumerator hostEnumerator = GetHostEnumerator();
            while (hostEnumerator.MoveNext())
            {
                hostList.Add(hostEnumerator.Current);
            }
            m_hostList = hostList;

            ArrayList assemblyList = new ArrayList();
            IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
            while (assemblyEnumerator.MoveNext())
            {
                assemblyList.Add(assemblyEnumerator.Current);
            }
            m_assemblyList = assemblyList;
        }

        /// <summary>
        ///     Finish deserializing legacy evidence
        /// </summary>
        [ComVisible(false)]
        [OnDeserialized]
        [SecurityCritical]
        private void OnDeserialized(StreamingContext context)
        {
            // Look at host and assembly evidence lists only if we serialized using Whidbey.
            if (m_evidence == null)
            {
                m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();

                // Whidbey evidence may need to be wrapped or added to a LegacyEvidenceList, so we go
                // through the legacy APIs to add them.
#pragma warning disable 618
                if (m_hostList != null)
                {
                    foreach (object evidenceObject in m_hostList)
                    {
                        if (evidenceObject != null)
                        {
                            AddHost(evidenceObject);
                        }
                    }

                    m_hostList = null;
                }

                if (m_assemblyList != null)
                {
                    foreach (object evidenceObject in m_assemblyList)
                    {
                        if (evidenceObject != null)
                        {
                            AddAssembly(evidenceObject);
                        }
                    }

                    m_assemblyList = null;
                }
#pragma warning restore 618
            }

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }
#endif // FEATURE_SERIALIZATION

        /// <summary>
        ///     Load any serialized evidence out of the target assembly into our evidence collection.
        ///     
        ///     We allow entry to this method with only a reader lock held, since most of the time we will
        ///     not need to write to the evidence dictionary. If we haven't yet deserialized the target
        ///     evidence, then we will upgrade to a writer lock at that point.
        /// </summary>
        private void DeserializeTargetEvidence()
        {
#if FEATURE_SERIALIZATION
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);

            if (m_target != null && !m_deserializedTargetEvidence)
            {
                bool upgradedLock = false;
                LockCookie lockCookie = new LockCookie();
                try
                {
                    if (!IsWriterLockHeld)
                    {
                        lockCookie = UpgradeToWriterLock();
                        upgradedLock = true;
                    }

                    // Set this to true here because AddAssemblyEvidenceNoLock will attempt to reenter this
                    // method creating possible infinite recursion.
                    m_deserializedTargetEvidence = true;

                    foreach (EvidenceBase targetEvidence in m_target.GetFactorySuppliedEvidence())
                    {
                        AddAssemblyEvidenceNoLock(targetEvidence, GetEvidenceIndexType(targetEvidence), DuplicateEvidenceAction.Throw);
                    }
                }
                finally
                {
                    if (upgradedLock)
                        DowngradeFromWriterLock(ref lockCookie);
                }
            }
#endif // FEATURE_SERIALIZATION
        }

#if FEATURE_SERIALIZATION
        /// <summary>
        ///     Serialize out raw evidence objects which have already been generated, ignoring any evidence
        ///     which might be present but has not yet been created for this assembly.
        ///     
        ///     This is used for indexing into the security policy cache, since we know that once policy is
        ///     resolved, the relevent membership conditions will have checked for any applicable evidence
        ///     and therefore after poliyc resolution this evidence collection will contain any evidence
        ///     objects necessary to arrive at its grant set.
        /// </summary>
        [SecurityCritical]
        internal byte[] RawSerialize()
        {
            try
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
                {
                    // Filter out any evidence which is not yet generated
                    Dictionary<Type, EvidenceBase> generatedEvidence = new Dictionary<Type, EvidenceBase>();
                    foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence)
                    {
                        if (evidenceType.Value != null && evidenceType.Value.HostEvidence != null)
                        {
                            generatedEvidence[evidenceType.Key] = evidenceType.Value.HostEvidence;
                        }
                    }

                    using (MemoryStream serializationStream = new MemoryStream())
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        formatter.Serialize(serializationStream, generatedEvidence);
                        return serializationStream.ToArray();
                    }
                }
            }
            catch (SecurityException)
            {
                // We're running in a context where it's not safe to serialize the evidence out.  In this case
                // Simply decline to cache the result of the policy evaluation
                return null;
            }
        }
#endif // FEATURE_SERIALIZATION

        //
        // ICollection implementation.  All ICollection interface members are potentially much more
        // expensive in Arrowhead then they were downlevel.  They should not be used if the standard Get and
        // Add methods will work instead.
        // 

        [Obsolete("Evidence should not be treated as an ICollection. Please use the GetHostEnumerator and GetAssemblyEnumerator methods rather than using CopyTo.")]
        public void CopyTo(Array array, int index)
        {
            if (array == null)
                throw new ArgumentNullException("array");
            if (index < 0 || index > array.Length - Count)
                throw new ArgumentOutOfRangeException("index");
            Contract.EndContractBlock();

            int currentIndex = index;

            IEnumerator hostEnumerator = GetHostEnumerator();
            while (hostEnumerator.MoveNext())
            {
                array.SetValue(hostEnumerator.Current, currentIndex);
                ++currentIndex;
            }

            IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
            while (assemblyEnumerator.MoveNext())
            {
                array.SetValue(assemblyEnumerator.Current, currentIndex);
                ++currentIndex;
            }
        }

        public IEnumerator GetHostEnumerator()
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host);
            }
        }

        public IEnumerator GetAssemblyEnumerator()
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                DeserializeTargetEvidence();
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Assembly);
            }
        }

        /// <summary>
        ///     Get an enumerator that can iterate over the raw evidence objects stored for the assembly
        /// </summary>
        internal RawEvidenceEnumerator GetRawAssemblyEvidenceEnumerator()
        {
            Contract.Assert(IsReaderLockHeld);
            DeserializeTargetEvidence();
            return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), false);
        }

        /// <summary>
        ///     Get an enumerator that can iterate over the raw evidence objects stored for the host
        /// </summary>
        /// <returns></returns>
        internal RawEvidenceEnumerator GetRawHostEvidenceEnumerator()
        {
            Contract.Assert(IsReaderLockHeld);
            return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), true);
        }

        [Obsolete("GetEnumerator is obsolete. Please use GetAssemblyEnumerator and GetHostEnumerator instead.")]
        public IEnumerator GetEnumerator()
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host | EvidenceEnumerator.Category.Assembly);
            }
        }

        /// <summary>
        ///     Get a specific type of assembly supplied evidence
        /// </summary>
        [ComVisible(false)]
        public T GetAssemblyEvidence<T>() where T : EvidenceBase
        {
            return UnwrapEvidence(GetAssemblyEvidence(typeof(T))) as T;
        }

        internal EvidenceBase GetAssemblyEvidence(Type type)
        {
            Contract.Assert(type != null);

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                return GetAssemblyEvidenceNoLock(type);
            }
        }

        private EvidenceBase GetAssemblyEvidenceNoLock(Type type)
        {
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(type != null);

            DeserializeTargetEvidence();
            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
            if (descriptor != null)
            {
                return descriptor.AssemblyEvidence;
            }

            return null;
        }

        /// <summary>
        ///     Get a specific type of host supplied evidence
        /// </summary>
        [ComVisible(false)]
        public T GetHostEvidence<T>() where T : EvidenceBase
        {
            return UnwrapEvidence(GetHostEvidence(typeof(T))) as T;
        }

        /// <summary>
        ///     Get a specific type of evidence from the host which may not have been verified yet.  If the
        ///     evidence was not verified, then don't mark it as being used yet.
        /// </summary>
        internal T GetDelayEvaluatedHostEvidence<T>() where T : EvidenceBase, IDelayEvaluatedEvidence
        {
            return UnwrapEvidence(GetHostEvidence(typeof(T), false)) as T;
        }

        internal EvidenceBase GetHostEvidence(Type type)
        {
            Contract.Assert(type != null);

            return GetHostEvidence(type, true);
        }

        [SecuritySafeCritical]
        private EvidenceBase GetHostEvidence(Type type, bool markDelayEvaluatedEvidenceUsed)
        {
            Contract.Assert(type != null);

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                EvidenceBase evidence = GetHostEvidenceNoLock(type);

                if (markDelayEvaluatedEvidenceUsed)
                {
                    IDelayEvaluatedEvidence delayEvidence = evidence as IDelayEvaluatedEvidence;
                    if (delayEvidence != null)
                    {
                        delayEvidence.MarkUsed();
                    }
                }

                return evidence;
            }
        }

        /// <summary>
        ///     Get host supplied evidence from the collection
        ///
        ///     We attempt to find host evdience in the following order:
        ///     
        ///       1. Already generated or explicitly supplied evidence
        ///       2. Evidence supplied by the CLR host
        ///       3. Evidence supplied by the CLR itself
        /// </summary>
        [SecurityCritical]
        private EvidenceBase GetHostEvidenceNoLock(Type type)
        {
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(type != null);

            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);

            // If the evidence descriptor doesn't exist for the host evidence type than the evidence doesn't
            // exist and neither the host nor the runtime can produce it.
            if (descriptor == null)
            {
                return null;
            }

            // If the evidence has already been generated or if it was explicitly provided then return that
            if (descriptor.HostEvidence != null)
            {
                return descriptor.HostEvidence;
            }

            // If we have a target, then the host or the runtime might be able to generate this type of
            // evidence on demand.
            if (m_target != null && !descriptor.Generated)
            {
                using (EvidenceUpgradeLockHolder lockHolder = new EvidenceUpgradeLockHolder(this))
                {
                    // Make sure that we don't attempt to generate this type of evidencea again if we fail to
                    // generate it now.
                    descriptor.Generated = true;

                    EvidenceBase generatedEvidence = GenerateHostEvidence(type, descriptor.HostCanGenerate);
                    if (generatedEvidence != null)
                    {
                        descriptor.HostEvidence = generatedEvidence;

                        //
                        // #BackpatchGeneratedEvidence
                        // 
                        // If we were cloned from another evidence collection propigate any generated evidence
                        // back to the original collection.  Since Assembly and AppDomain both clone their
                        // evidence before giving it to users, this prevents us from having to regenerate
                        // evidence types on each clone that gets created.  Note that we do not want to do this
                        // backpatching if the origin already has evidence of this type or if it has had
                        // this type of evidence removed from its collection.
                        //

                        Evidence cloneOrigin = m_cloneOrigin != null ? m_cloneOrigin.Target as Evidence : null;
                        if (cloneOrigin != null)
                        {
                            BCLDebug.Assert(cloneOrigin.Target != null && cloneOrigin.Target == Target,
                                            "Attempt to backpatch evidence to a collection with a different target.");

                            using (EvidenceLockHolder cloneLockHolder = new EvidenceLockHolder(cloneOrigin, EvidenceLockHolder.LockType.Writer))
                            {
                                EvidenceTypeDescriptor cloneDescriptor = cloneOrigin.GetEvidenceTypeDescriptor(type);
                                if (cloneDescriptor != null && cloneDescriptor.HostEvidence == null)
                                {
                                    cloneDescriptor.HostEvidence = generatedEvidence.Clone() as EvidenceBase;
                                }
                            }
                        }

                    }

                    return generatedEvidence;
                }
            }

            // The evidence could not be generated and was not found
            return null;
        }

        /// <summary>
        ///     Attempt to generate host evidence on demand via calls to the runtime host or the evidence facotry
        /// </summary>
        [SecurityCritical]
        private EvidenceBase GenerateHostEvidence(Type type, bool hostCanGenerate)
        {
            Contract.Assert(type != null);
            Contract.Assert(IsWriterLockHeld);

#if FEATURE_CAS_POLICY
            // First let the host generate the evidence if it can.
            if (hostCanGenerate)
            {
                AppDomain targetDomain = m_target.Target as AppDomain;
                Assembly targetAssembly = m_target.Target as Assembly;

                EvidenceBase hostEvidence = null;
                if (targetDomain != null)
                {
                    hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAppDomainEvidence(type);
                }
                else if (targetAssembly != null)
                {
                    hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAssemblyEvidence(type, targetAssembly);
                }

                // If the host generated the evidence, verify that it generated the evidence we expected
                // and use that.
                if (hostEvidence != null)
                {
                    if (!type.IsAssignableFrom(hostEvidence.GetType()))
                    {
                        string hostType = AppDomain.CurrentDomain.HostSecurityManager.GetType().FullName;
                        string recievedType = hostEvidence.GetType().FullName;
                        string requestedType = type.FullName;

                        throw new InvalidOperationException(Environment.GetResourceString("Policy_IncorrectHostEvidence", hostType, recievedType, requestedType));
                    }

                    return hostEvidence;
                }
            }
#endif // FEATURE_CAS_POLICY

            // Finally, check to see if the CLR can generate the evidence
            return m_target.GenerateEvidence(type);
        }

        [Obsolete("Evidence should not be treated as an ICollection. Please use GetHostEnumerator and GetAssemblyEnumerator to iterate over the evidence to collect a count.")]
        public int Count
        {
            get
            {
                int count = 0;

                IEnumerator hostEvidence = GetHostEnumerator();
                while (hostEvidence.MoveNext())
                {
                    ++count;
                }

                IEnumerator assemblyEvidence = GetAssemblyEnumerator();
                while (assemblyEvidence.MoveNext())
                {
                    ++count;
                }

                return count;
            }
        }

        /// <summary>
        ///     Get the number of pieces of evidence which are currently generated, without causing any
        ///     lazily generated evidence to be created.
        /// </summary>
        [ComVisible(false)]
        internal int RawCount
        {
            get
            {
                int count = 0;

                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
                {
                    foreach (Type evidenceType in new List<Type>(m_evidence.Keys))
                    {
                        EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType);

                        if (descriptor != null)
                        {
                            if (descriptor.AssemblyEvidence != null)
                            {
                                ++count;
                            }
                            if (descriptor.HostEvidence != null)
                            {
                                ++count;
                            }
                        }
                    }
                }

                return count;
            }
        }

        public Object SyncRoot
        {
            get { return this; }
        }

        public bool IsSynchronized
        {
            get { return true; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

#if FEATURE_CAS_POLICY
        [ComVisible(false)]
        public Evidence Clone()
        {
            return new Evidence(this);
        }
#endif // FEATURE_CAS_POLICY

        [ComVisible(false)]
        [SecuritySafeCritical]
        public void Clear()
        {
            if (Locked)
            {
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                ++m_version;
                m_evidence.Clear();
            }
        }

        [ComVisible(false)]
        [SecuritySafeCritical]
        public void RemoveType(Type t)
        {
            if (t == null)
                throw new ArgumentNullException("t");
            Contract.EndContractBlock();

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(t);
                if (descriptor != null)
                {
                    ++m_version;

                    // If we've locked this evidence collection, we need to do the lock check in the case that 
                    // either we have host evidence, or that the host might generate it, since removing the
                    // evidence will cause us to bypass the host's ability to ever generate the evidence.
                    if (Locked && (descriptor.HostEvidence != null || descriptor.HostCanGenerate))
                    {
                        new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
                    }

                    m_evidence.Remove(t);
                }
            }
        }

        /// <summary>
        ///     Mark all of the already generated evidence in the collection as having been used during a
        ///     policy evaluation.
        /// </summary>
        internal void MarkAllEvidenceAsUsed()
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence)
                {
                    if (evidenceType.Value != null)
                    {
                        IDelayEvaluatedEvidence hostEvidence = evidenceType.Value.HostEvidence as IDelayEvaluatedEvidence;
                        if (hostEvidence != null)
                        {
                            hostEvidence.MarkUsed();
                        }

                        IDelayEvaluatedEvidence assemblyEvidence = evidenceType.Value.AssemblyEvidence as IDelayEvaluatedEvidence;
                        if (assemblyEvidence != null)
                        {
                            assemblyEvidence.MarkUsed();
                        }
                    }
                }
            }
        }

#if FEATURE_CAS_POLICY
        /// <summary>
        ///     Determine if delay evaluated strong name evidence is contained in this collection, and if so
        ///     if it was used during policy evaluation.
        ///     
        ///     This method is called from the VM in SecurityPolicy::WasStrongNameEvidenceUsed
        ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to
        ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the
        ///     internal data structures holding the evidence objects in the Evidence class.
        /// </summary>
        private bool WasStrongNameEvidenceUsed()
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                EvidenceTypeDescriptor snTypeDescriptor = GetEvidenceTypeDescriptor(typeof(StrongName));
                if (snTypeDescriptor != null)
                {
                    IDelayEvaluatedEvidence snEvidence = snTypeDescriptor.HostEvidence as IDelayEvaluatedEvidence;
                    return snEvidence != null && snEvidence.WasUsed;
                }

                return false;
            }
        }
#endif // FEATURE_CAS_POLICY

        /// <summary>
        ///     Utility class to wrap acquiring a lock onto the evidence collection
        /// </summary>
        private class EvidenceLockHolder : IDisposable
        {
            private Evidence m_target;
            private LockType m_lockType;

            public enum LockType
            {
                Reader,
                Writer
            }

            public EvidenceLockHolder(Evidence target, LockType lockType)
            {
                Contract.Assert(target != null);
                Contract.Assert(lockType == LockType.Reader || lockType == LockType.Writer);

                m_target = target;
                m_lockType = lockType;

                if (m_lockType == LockType.Reader)
                {
                    m_target.AcquireReaderLock();
                }
                else
                {
                    m_target.AcquireWriterlock();
                }
            }

            public void Dispose()
            {
                if (m_lockType == LockType.Reader && m_target.IsReaderLockHeld)
                {
                    m_target.ReleaseReaderLock();
                }
                else if (m_lockType == LockType.Writer && m_target.IsWriterLockHeld)
                {
                    m_target.ReleaseWriterLock();
                }
            }
        }

        /// <summary>
        ///     Utility class to wrap upgrading an acquired reader lock to a writer lock and then
        ///     downgrading it back to a reader lock.
        /// </summary>
        private class EvidenceUpgradeLockHolder : IDisposable
        {
            private Evidence m_target;
            private LockCookie m_cookie;

            public EvidenceUpgradeLockHolder(Evidence target)
            {
                Contract.Assert(target != null);

                m_target = target;
                m_cookie = m_target.UpgradeToWriterLock();
            }

            public void Dispose()
            {
                if (m_target.IsWriterLockHeld)
                {
                    m_target.DowngradeFromWriterLock(ref m_cookie);
                }
            }
        }

        /// <summary>
        ///     Enumerator that iterates directly over the evidence type map, returning back the evidence objects
        ///     that are contained in it.  This enumerator will generate any lazy evaluated evidence it finds,
        ///     but it does not attempt to deal with legacy evidence adapters.
        ///     
        ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to
        ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the
        ///     internal data structures holding the evidence objects in the Evidence class.
        /// </summary>
        internal sealed class RawEvidenceEnumerator : IEnumerator<EvidenceBase>
        {
            private Evidence m_evidence;
            private bool m_hostEnumerator;      // true to enumerate host evidence, false to enumerate assembly evidence
            private uint m_evidenceVersion;

            private Type[] m_evidenceTypes;
            private int m_typeIndex;
            private EvidenceBase m_currentEvidence;

            private static volatile List<Type> s_expensiveEvidence;

            public RawEvidenceEnumerator(Evidence evidence, IEnumerable<Type> evidenceTypes, bool hostEnumerator)
            {
                Contract.Assert(evidence != null);
                Contract.Assert(evidenceTypes != null);

                m_evidence = evidence;
                m_hostEnumerator = hostEnumerator;
                m_evidenceTypes = GenerateEvidenceTypes(evidence, evidenceTypes, hostEnumerator);
                m_evidenceVersion = evidence.m_version;

                Reset();
            }

            public EvidenceBase Current
            {
                get
                {
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));

                    return m_currentEvidence;
                }
            }

            object IEnumerator.Current
            {
                get
                {
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));

                    return m_currentEvidence;
                }
            }

            /// <summary>
            ///     List of types of evidence that we would like to avoid generating if possible
            /// </summary>
            private static List<Type> ExpensiveEvidence
            {
                get
                {
                    if (s_expensiveEvidence == null)
                    {
                        List<Type> expensiveEvidence = new List<Type>();
#if FEATURE_CAS_POLICY
                        expensiveEvidence.Add(typeof(Hash));
                        expensiveEvidence.Add(typeof(Publisher));
#endif // FEATURE_CAS_POLICY
                        s_expensiveEvidence = expensiveEvidence;

#if _DEBUG
                        List<Type> runtimeTypes = new List<Type>(Evidence.RuntimeEvidenceTypes);
                        foreach (Type expensiveType in s_expensiveEvidence)
                        {
                            BCLDebug.Assert(runtimeTypes.Contains(expensiveType),
                                            "Evidence type not generated by the runtime found in expensive evidence type list");
                        }
#endif // _DEBUG
                    }

                    return s_expensiveEvidence;
                }
            }

            public void Dispose()
            {
                return;
            }

            /// <summary>
            ///     Generate the array of types of evidence that could have values for
            /// </summary>
            private static Type[] GenerateEvidenceTypes(Evidence evidence,
                                                        IEnumerable<Type> evidenceTypes,
                                                        bool hostEvidence)
            {
                Contract.Assert(evidence != null);
                Contract.Assert(evidenceTypes != null);

                //
                // Sort the evidence being generated into three categories, which we enumerate in order:
                //   1. Evidence which has already been generated
                //   2. Evidence which is relatively inexpensive to generate
                //   3. Evidence which is expensive to generate.
                //   
                // This allows us to be as efficient as possible in case the user of the enumerator stops the
                // enumeration before we step up to the next more expensive category.
                //

                List<Type> alreadyGeneratedList = new List<Type>();
                List<Type> inexpensiveList = new List<Type>();
                List<Type> expensiveList = new List<Type>(ExpensiveEvidence.Count);

                // Iterate over the evidence types classifying into the three groups.  We need to copy the list
                // here since GetEvidenceTypeDescriptor will potentially update the evidence dictionary, which
                // evidenceTypes iterates over.
                foreach (Type evidenceType in evidenceTypes)
                {
                    EvidenceTypeDescriptor descriptor = evidence.GetEvidenceTypeDescriptor(evidenceType);
                    BCLDebug.Assert(descriptor != null, "descriptor != null");

                    bool alreadyGenerated = (hostEvidence && descriptor.HostEvidence != null) ||
                                            (!hostEvidence && descriptor.AssemblyEvidence != null);

                    if (alreadyGenerated)
                    {
                        alreadyGeneratedList.Add(evidenceType);
                    }
                    else if (ExpensiveEvidence.Contains(evidenceType))
                    {
                        expensiveList.Add(evidenceType);
                    }
                    else
                    {
                        inexpensiveList.Add(evidenceType);
                    }
                }

                Type[] enumerationTypes = new Type[alreadyGeneratedList.Count + inexpensiveList.Count + expensiveList.Count];
                alreadyGeneratedList.CopyTo(enumerationTypes, 0);
                inexpensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count);
                expensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count + inexpensiveList.Count);

                return enumerationTypes;
            }

            [SecuritySafeCritical]
            public bool MoveNext()
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
                {
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));

                    m_currentEvidence = null;

                    // Iterate over the possible types of evidence that we could have until we find one that
                    // really exists, or we run out of posibilities.
                    do
                    {
                        ++m_typeIndex;

                        if (m_typeIndex < m_evidenceTypes.Length)
                        {
                            if (m_hostEnumerator)
                            {
                                m_currentEvidence = m_evidence.GetHostEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
                            }
                            else
                            {
                                m_currentEvidence = m_evidence.GetAssemblyEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
                            }
                        }
                    }
                    while (m_typeIndex < m_evidenceTypes.Length && m_currentEvidence == null);
                }

                return m_currentEvidence != null;
            }

            public void Reset()
            {
                if (m_evidence.m_version != m_evidenceVersion)
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));

                m_typeIndex = -1;
                m_currentEvidence = null;
            }
        }

        private sealed class EvidenceEnumerator : IEnumerator
        {
            private Evidence m_evidence;
            private Category m_category;
            private Stack m_enumerators;

            private object m_currentEvidence;

            [Flags]
            internal enum Category
            {
                Host = 0x1,     // Enumerate only host supplied evidence
                Assembly = 0x2      // Enumerate only assembly supplied evidence
            }

            internal EvidenceEnumerator(Evidence evidence, Category category)
            {
                Contract.Assert(evidence != null);
                Contract.Assert(evidence.IsReaderLockHeld);

                m_evidence = evidence;
                m_category = category;
                ResetNoLock();
            }

            public bool MoveNext()
            {
                IEnumerator currentEnumerator = CurrentEnumerator;

                // No more enumerators means we can't go any further
                if (currentEnumerator == null)
                {
                    m_currentEvidence = null;
                    return false;
                }

                // See if the current enumerator can continue
                if (currentEnumerator.MoveNext())
                {
                    //
                    // If we've found an adapter for legacy evidence, we need to unwrap it for it to be the
                    // current enumerator's value.  For wrapped evidence, this is a simple unwrap, for a list of
                    // evidence, we need to make that the current enumerator and get its first value.
                    // 

                    LegacyEvidenceWrapper legacyWrapper = currentEnumerator.Current as LegacyEvidenceWrapper;
                    LegacyEvidenceList legacyList = currentEnumerator.Current as LegacyEvidenceList;

                    if (legacyWrapper != null)
                    {
                        m_currentEvidence = legacyWrapper.EvidenceObject;
                    }
                    else if (legacyList != null)
                    {
                        IEnumerator legacyListEnumerator = legacyList.GetEnumerator();
                        m_enumerators.Push(legacyListEnumerator);
                        MoveNext();
                    }
                    else
                    {
                        m_currentEvidence = currentEnumerator.Current;
                    }

                    BCLDebug.Assert(m_currentEvidence != null, "m_currentEvidence != null");
                    return true;
                }
                else
                {
                    // If we've reached the end of the current enumerator, move to the next one and try again
                    m_enumerators.Pop();
                    return MoveNext();
                }
            }

            public object Current
            {
                get { return m_currentEvidence; }
            }

            private IEnumerator CurrentEnumerator
            {
                get
                {
                    return m_enumerators.Count > 0 ? m_enumerators.Peek() as IEnumerator : null;
                }
            }

            public void Reset()
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
                {
                    ResetNoLock();
                }
            }

            private void ResetNoLock()
            {
                Contract.Assert(m_evidence != null);
                Contract.Assert(m_evidence.IsReaderLockHeld);

                m_currentEvidence = null;
                m_enumerators = new Stack();

                if ((m_category & Category.Host) == Category.Host)
                {
                    m_enumerators.Push(m_evidence.GetRawHostEvidenceEnumerator());
                }
                if ((m_category & Category.Assembly) == Category.Assembly)
                {
                    m_enumerators.Push(m_evidence.GetRawAssemblyEvidenceEnumerator());
                }
            }
        }
#endif //!FEATURE_CORECLR && FEATURE_RWLOCK
    }
}