From a8435c8849f6589d0af98146cd38ebad053dc848 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:35:50 -0700 Subject: [PATCH 1/6] moved add'l remarks back to this repo --- .../Overview/Project.csproj | 8 + .../Overview/multiple1.cs | 23 +++ .../Overview/multiple2.cs | 26 +++ .../GetHashCode/gethashcodeex1.cs | 51 ++++++ .../ICustomMarshaler/Overview/Project.csproj | 8 + .../ICustomMarshaler/Overview/source.cs | 65 ++++++++ .../Overview/Project.vbproj | 8 + .../Overview/multiple1.vb | 21 +++ .../Overview/multiple2.vb | 23 +++ .../RuntimeHelpers/GetHashCode/Project.vbproj | 8 + .../GetHashCode/gethashcodeex1.vb | 52 ++++++ .../ICustomMarshaler/Overview/Project.vbproj | 8 + .../ICustomMarshaler/Overview/source.vb | 47 ++++++ .../Overview/Project.vbproj | 8 + .../Overview/apply1.vb | 57 +++++++ .../InternalsVisibleToAttribute.xml | 57 ++++++- .../RuntimeHelpers.xml | 44 +++++- .../COMException.xml | 29 +++- .../ComWrappers.xml | 55 ++++++- .../ICustomMarshaler.xml | 149 +++++++++++++++++- .../SafeHandle.xml | 37 ++++- .../AssemblyLoadContext.xml | 56 ++++++- .../DataContractAttribute.xml | 43 ++++- .../DataContractSerializer.xml | 47 +++++- .../IExtensibleDataObject.xml | 22 ++- .../XsdDataContractExporter.xml | 31 +++- .../ComponentGuaranteesAttribute.xml | 127 ++++++++++++++- 27 files changed, 1098 insertions(+), 12 deletions(-) create mode 100644 snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj create mode 100644 snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs create mode 100644 snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs create mode 100644 snippets/csharp/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.cs create mode 100644 snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.csproj create mode 100644 snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/Project.vbproj create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.vb create mode 100644 snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.vbproj create mode 100644 snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb create mode 100644 snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/Project.vbproj create mode 100644 snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs new file mode 100644 index 00000000000..25b9cbfd39e --- /dev/null +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.CompilerServices; + +// +[assembly:InternalsVisibleTo("Friend1a")] +[assembly:InternalsVisibleTo("Friend1b")] +// + +public class StringUtilities +{ + internal string ToTitleCase(string value) + { + string retval = null; + for (int ctr = 0; ctr <= value.Length - 1; ctr++) + if (ctr == 0) + retval += Char.ToUpper(value[ctr]); + else if (ctr > 0 && Char.IsWhiteSpace(value[ctr - 1])) + retval += Char.ToUpper(value[ctr]); + else + retval += value[ctr]; + return retval; + } +} diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs new file mode 100644 index 00000000000..981dd1b35e9 --- /dev/null +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.CompilerServices; + +// +[assembly:InternalsVisibleTo("Friend2a"), + InternalsVisibleTo("Friend2b")] +// + +namespace Utilities +{ + public class StringUtilities + { + internal static string ToTitleCase(string value) + { + string retval = null; + for (int ctr = 0; ctr <= value.Length - 1; ctr++) + if (ctr == 0) + retval += Char.ToUpper(value[ctr]); + else if (ctr > 0 && Char.IsWhiteSpace(value[ctr - 1])) + retval += Char.ToUpper(value[ctr]); + else + retval += value[ctr]; + return retval; + } + } +} \ No newline at end of file diff --git a/snippets/csharp/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.cs b/snippets/csharp/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.cs new file mode 100644 index 00000000000..c58d72ac74c --- /dev/null +++ b/snippets/csharp/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.cs @@ -0,0 +1,51 @@ +// +using System; +using System.Runtime.CompilerServices; + +public class Example +{ + public static void Main() + { + Console.WriteLine("{0,-18} {1,6} {2,18:N0} {3,6} {4,18:N0}\n", + "", "Var 1", "Hash Code", "Var 2", "Hash Code"); + + // Get hash codes of two different strings. + String sc1 = "String #1"; + String sc2 = "String #2"; + ShowHashCodes("sc1", sc1, "sc2", sc2); + + // Get hash codes of two identical non-interned strings. + String s1 = "This string"; + String s2 = String.Format("{0} {1}", "This", "string"); + ShowHashCodes("s1", s1, "s2", s2); + + // Get hash codes of two (evidently concatenated) strings. + String si1 = "This is a string!"; + String si2 = "This " + "is " + "a " + "string!"; + ShowHashCodes("si1", si1, "si2", si2); + } + + private static void ShowHashCodes(String var1, Object value1, + String var2, Object value2) + { + Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}", + "Obj.GetHashCode", var1, value1.GetHashCode(), + var2, value2.GetHashCode()); + + Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}\n", + "RTH.GetHashCode", var1, RuntimeHelpers.GetHashCode(value1), + var2, RuntimeHelpers.GetHashCode(value2)); + } +} +// The example displays output similar to the following: +// Var 1 Hash Code Var 2 Hash Code +// +// Obj.GetHashCode sc1 94EABD27 sc2 94EABD24 +// RTH.GetHashCode sc1 02BF8098 sc2 00BB8560 +// +// Obj.GetHashCode s1 29C5A397 s2 29C5A397 +// RTH.GetHashCode s1 0297B065 s2 03553390 +// +// Obj.GetHashCode si1 941BCEA5 si2 941BCEA5 +// RTH.GetHashCode si1 01FED012 si2 01FED012 +// diff --git a/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.csproj b/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.csproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.csproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs b/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs new file mode 100644 index 00000000000..a86d65aa132 --- /dev/null +++ b/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs @@ -0,0 +1,65 @@ +using System; +// +using System.Runtime.InteropServices; +// + +// +public interface INew +{ + void NewMethod(); +} +// + +// +public interface ICustomMarshaler +{ + Object MarshalNativeToManaged(IntPtr pNativeData); + IntPtr MarshalManagedToNative(Object ManagedObj); + void CleanUpNativeData(IntPtr pNativeData); + void CleanUpManagedData(Object ManagedObj); + int GetNativeDataSize(); +} +// + +namespace scope1 +{ + // + interface IUserData + { + void DoSomeStuff(INew pINew); + } + // +} + +namespace scope2 +{ + // + interface IUserData + { + void DoSomeStuff( + [MarshalAs(UnmanagedType.CustomMarshaler, + MarshalType="NewOldMarshaler")] + INew pINew + ); + } + // +} + +// +public class NewOldMarshaler : ICustomMarshaler +{ + public static ICustomMarshaler GetInstance(string pstrCookie) + => new NewOldMarshaler(); + + public Object MarshalNativeToManaged(IntPtr pNativeData) => throw new NotImplementedException(); + public IntPtr MarshalManagedToNative(Object ManagedObj) => throw new NotImplementedException(); + public void CleanUpNativeData(IntPtr pNativeData) => throw new NotImplementedException(); + public void CleanUpManagedData(Object ManagedObj) => throw new NotImplementedException(); + public int GetNativeDataSize() => throw new NotImplementedException(); +} +// + +class StubClass +{ + public static void Main() { } +} diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb new file mode 100644 index 00000000000..24e7e90f237 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb @@ -0,0 +1,21 @@ +Imports System.Runtime.CompilerServices + +' + + +' +Public Class StringUtilities + Friend Function ToTitleCase(value As String) As String + Dim retval As String = Nothing + For ctr As Integer = 0 To value.Length - 1 + If ctr = 0 Then + retval += Char.ToUpper(value(ctr)) + ElseIf ctr > 0 AndAlso Char.IsWhiteSpace(value(ctr - 1)) + retval += Char.ToUpper(value(ctr)) + Else + retval += value(ctr) + End If + Next + Return retval + End Function +End Class diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb new file mode 100644 index 00000000000..54c1b82611a --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb @@ -0,0 +1,23 @@ +Imports System.Runtime.CompilerServices + +' + +' +Namespace Utilities + Public Class StringUtilities + Shared Friend Function ToTitleCase(value As String) As String + Dim retval As String = Nothing + For ctr As Integer = 0 To value.Length - 1 + If ctr = 0 Then + retval += Char.ToUpper(value(ctr)) + ElseIf ctr > 0 AndAlso Char.IsWhiteSpace(value(ctr - 1)) + retval += Char.ToUpper(value(ctr)) + Else + retval += value(ctr) + End If + Next + Return retval + End Function + End Class +End Namespace \ No newline at end of file diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/Project.vbproj b/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/Project.vbproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/Project.vbproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.vb b/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.vb new file mode 100644 index 00000000000..23afc1bd622 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.vb @@ -0,0 +1,52 @@ +' Visual Basic .NET Document +Option Strict On + +' +Imports System.Runtime.CompilerServices + +Module Example + Public Sub Main() + Console.WriteLine("{0,-18} {1,6} {2,18:N0} {3,6} {4,18:N0}", + "", "Var 1", "Hash Code", "Var 2", "Hash Code") + Console.WriteLine() + + ' Get hash codes of two different strings. + Dim sc1 As String = "String #1" + Dim sc2 As String = "String #2" + ShowHashCodes("sc1", sc1, "sc2", sc2) + + ' Get hash codes of two identical non-interned strings. + Dim s1 As String = "This string" + Dim s2 As String = String.Format("{0} {1}", "This", "string") + ShowHashCodes("s1", s1, "s2", s2) + + ' Get hash codes of two (evidently concatenated) strings. + Dim si1 As String = "This is a string!" + Dim si2 As String = "This " + "is " + "a " + "string!" + ShowHashCodes("si1", si1, "si2", si2) + End Sub + + Private Sub ShowHashCodes(var1 As String, value1 As Object, + var2 As String, value2 As Object) + Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}", + "Obj.GetHashCode", var1, value1.GetHashCode, + var2, value2.GetHashCode) + + Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}", + "RTH.GetHashCode", var1, RuntimeHelpers.GetHashCode(value1), + var2, RuntimeHelpers.GetHashCode(value2)) + Console.WriteLine() + End Sub +End Module +' The example displays output similar to the following: +' Var 1 Hash Code Var 2 Hash Code +' +' Obj.GetHashCode sc1 94EABD27 sc2 94EABD24 +' RTH.GetHashCode sc1 02BF8098 sc2 00BB8560 +' +' Obj.GetHashCode s1 29C5A397 s2 29C5A397 +' RTH.GetHashCode s1 0297B065 s2 03553390 +' +' Obj.GetHashCode si1 941BCEA5 si2 941BCEA5 +' RTH.GetHashCode si1 01FED012 si2 01FED012 +' diff --git a/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.vbproj b/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.vbproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/Project.vbproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb b/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb new file mode 100644 index 00000000000..0b0c06adb87 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb @@ -0,0 +1,47 @@ +' +Imports System.Runtime.InteropServices + +' + +' +Public Interface INew + Sub NewMethod() +End Interface +' + + +' +Public Interface ICustomMarshaler + Function MarshalNativeToManaged( pNativeData As IntPtr ) As Object + Function MarshalManagedToNative( ManagedObj As Object ) As IntPtr + Sub CleanUpNativeData( pNativeData As IntPtr ) + Sub CleanUpManagedData( ManagedObj As Object ) + Function GetNativeDataSize() As Integer +End Interface +' + +Namespace scope1 + +' +Public Interface IUserData + Sub DoSomeStuff(pINew As INew) +End Interface +' + +End Namespace + +Namespace scope2 + +' +Public Interface IUserData + Sub DoSomeStuff( _ + pINew As INew) +End Interface +' +End Namespace + +Class StubClass + Public Shared Sub Main + End Sub +End Class \ No newline at end of file diff --git a/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/Project.vbproj b/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/Project.vbproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/Project.vbproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb b/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb new file mode 100644 index 00000000000..bd3f3de6b18 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb @@ -0,0 +1,57 @@ +' Visual Basic .NET Document +Option Strict On + +Imports System.Reflection +Imports System.Runtime.Versioning + + +Namespace MyLibrary + Public Class MyLibraryClass + Public Function GetName() As String + Return "My Library" + End Function + End Class + + Public Class MyPrimitiveClass + + End Class + + Public Class MyChurningClass + + End Class +End Namespace + +Public Module Example + Public Sub Main() + Dim assem As Assembly = GetType(Example).Assembly + For Each typ As Type In assem.GetTypes() + Dim typeAttribs() As Object = typ.GetCustomAttributes(GetType(ComponentGuaranteesAttribute), True) + If typeAttribs.Length > 0 Then + Dim guaranteeAttrib As ComponentGuaranteesAttribute = DirectCast(typeAttribs(0), ComponentGuaranteesAttribute) + Dim guarantee = guaranteeAttrib.Guarantees + ' Test whether guarantee is Exchange. + If (guarantee And ComponentGuaranteesOptions.Exchange) = ComponentGuaranteesOptions.Exchange Then + Console.WriteLine("{0} is marked as {1}.", typ.Name, guarantee) + End If + ' + ' Test whether guarantee is Stable. + If (guarantee And ComponentGuaranteesOptions.Stable) = ComponentGuaranteesOptions.Stable Then + Console.WriteLine("{0} is marked as {1}.", typ.Name, guarantee) + End If + ' + ' + ' Test whether guarantee is Stable or Exchange. + If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) > 0 Then + Console.WriteLine("{0} is marked as Stable or Exchange.", typ.Name, guarantee) + End If + ' + ' + ' Test whether there is no guarantee (neither Stable nor Exchange). + If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) = 0 Then + Console.WriteLine("{0} has no compatibility guarantee.", typ.Name, guarantee) + End If + ' + End If + Next + End Sub +End Module diff --git a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml index aa8511d58a6..3dbede95aee 100644 --- a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml +++ b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml @@ -58,7 +58,62 @@ Specifies that types that are ordinarily visible only within the current assembly are visible to a specified assembly. - For more information about this API, see Supplemental API remarks for InternalsVisibleToAttribute. + + attribute specifies that types that are ordinarily visible only within the current assembly are visible to a specified assembly. + +Ordinarily, types and members with [`internal` scope in C#](/dotnet/csharp/language-reference/keywords/internal) or [`Friend` scope in Visual Basic](/dotnet/visual-basic/language-reference/modifiers/friend) are visible only in the assembly in which they are defined. Types and members with [`protected internal`](/dotnet/csharp/language-reference/keywords/protected-internal) scope ([`Protected Friend`](/dotnet/visual-basic/language-reference/modifiers/protected-friend) scope in Visual Basic) are visible only in their own assembly or to types that derive from their containing class. Types and members with [`private protected`](/dotnet/csharp/language-reference/keywords/private-protected) scope ([`Private Protected`](/dotnet/visual-basic/language-reference/modifiers/private-protected) scope in Visual Basic) are visible in the containing class or in types that derive from their containing class within the current assembly + +The attribute makes these types and members also visible to the types in a specified assembly, which is known as a friend assembly. This applies only to `internal` (`Friend` in Visual Basic), `protected internal`(`Protected Friend` in Visual Basic), and `private protected` (`Private Protected` in Visual Basic) members, but not `private` ones. + +> [!NOTE] +> In the case of `private protected` (`Private Protected` in Visual Basic) members, the attribute extends accessibility only to types that derive from the *containing class* of the member. + +The attribute is applied at the assembly level. This means that it can be included at the beginning of a source code file, or it can be included in the AssemblyInfo file in a Visual Studio project. You can use the attribute to specify a single friend assembly that can access the internal types and members of the current assembly. You can define multiple friend assemblies in two ways. They can appear as individual assembly-level attributes, as the following example illustrates. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs" id="Snippet3"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb" id="Snippet3"::: + +They can also appear with separate tags but a single `assembly` keyword, as the following example illustrates. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs" id="Snippet4"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb" id="Snippet4"::: + +The friend assembly is identified by the constructor. Both the current assembly and the friend assembly must be unsigned, or both assemblies must be signed with a strong name. + +If both assemblies are unsigned, the `assemblyName` argument consists of the name of the friend assembly, specified without a directory path or file name extension. + +If both assemblies are signed with a strong name, the argument to the constructor must consist of the name of the assembly without its directory path or file name extension, along with the full public key (and not its public key token). To get the full public key of a strong-named assembly, see the [Get the full public key](#get-the-full-public-key) section later in this article. For more information about using with strong-named assemblies, see the constructor. + +Do not include values for the , , or field in the argument; the Visual Basic, C#, and C++ compilers treat this as a compiler error. If you use a compiler that does not treat it as an error (such as the [IL Assembler (ILAsm.exe)](/dotnet/framework/tools/ilasm-exe-il-assembler)) and the assemblies are strong-named, a exception is thrown the first time the specified friend assembly accesses the assembly that contains the attribute. + +For more information about how to use this attribute, see [Friend assemblies](/dotnet/standard/assembly/friend) and [C++ friend assemblies](/cpp/dotnet/friend-assemblies-cpp). + +## Get the full public key + +You can use the [Strong Name Tool (Sn.exe)](/dotnet/framework/tools/sn-exe-strong-name-tool) to retrieve the full public key from a strong-named key (.snk) file. To do this, you perform the following steps: + +1. Extract the public key from the strong-named key file to a separate file: + + `Sn -p ` + +2. Display the full public key to the console: + + `Sn -tp ` + +3. Copy and paste the full public key value into your source code. + +## Compile the friend assembly with C\# + +If you use the C# compiler to compile the friend assembly, you must explicitly specify the name of the output file (.exe or .dll) by using the **/out** compiler option. This is required because the compiler has not yet generated the name for the assembly it is building at the time it is binding to external references. The **/out** compiler option is optional for the Visual Basic compiler, and the corresponding **-out** or **-o** compiler option should not be used when compiling friend assemblies with the F# compiler. + +## Compile the friend assembly with C++ + +In C++, in order to make the internal members enabled by the attribute accessible to a friend assembly, you must use the `as_friend` attribute in the C++ directive. For more information, see [Friend Assemblies (C++)](/cpp/dotnet/friend-assemblies-cpp). + + ]]> + An object to retrieve the hash code for. Serves as a hash function for a particular object, and is suitable for use in algorithms and data structures that use hash codes, such as a hash table. A hash code for the object identified by the parameter. - For more information about this API, see Supplemental API remarks for RuntimeHelpers.GetHashCode. + + method always calls the method non-virtually, even if the object's type has overridden the method. Therefore, using might differ from calling `GetHashCode` directly on the object with the method. + +> [!WARNING] +> Although the method returns identical hash codes for identical object references, you should not use this method to test for object identity, because this hash code does not uniquely identify an object reference. To test for object identity (that is, to test that two objects reference the same object in memory), call the method. Nor should you use to test whether two strings represent equal object references, because the string is interned. To test for string interning, call the method. + +The and methods differ as follows: + +- returns a hash code that is based on the object's definition of equality. For example, two strings with identical contents will return the same value for . +- returns a hash code that indicates object identity. That is, two string variables whose contents are identical and that represent a string that is interned (see the [String Interning](#string-interning) section) or that represent a single string in memory return identical hash codes. + +> [!IMPORTANT] +> Note that always returns identical hash codes for equal object references. However, the reverse is not true: equal hash codes do not indicate equal object references. A particular hash code value is not unique to a particular object reference; different object references can generate identical hash codes. + +This method is used by compilers. + +## String interning + +The common language runtime (CLR) maintains an internal pool of strings and stores literals in the pool. If two strings (for example, `str1` and `str2`) are formed from an identical string literal, the CLR will set `str1` and `str2` to point to the same location on the managed heap to conserve memory. Calling on these two string objects will produce the same hash code, contrary to the second bulleted item in the previous section. + +The CLR adds only literals to the pool. Results of string operations such as concatenation are not added to the pool, unless the compiler resolves the string concatenation as a single string literal. Therefore, if `str2` was created as the result of a concatenation operation, and `str2` is identical to `str1`, using on these two string objects will not produce the same hash code. + +If you want to add a concatenated string to the pool explicitly, use the method. + +You can also use the method to check whether a string has an interned reference. + +## Examples + +The following example demonstrates the difference between the and methods. The output from the example illustrates the following: + +- Both sets of hash codes for the first set of strings passed to the `ShowHashCodes` method are different, because the strings are completely different. + +- generates the same hash code for the second set of strings passed to the `ShowHashCodes` method, because the strings are equal. However, the method does not. The first string is defined by using a string literal and so is interned. Although the value of the second string is the same, it is not interned, because it is returned by a call to the method. + +- In the case of the third string, the hash codes produced by for both strings are identical, as are the hash codes produced by . This is because the compiler has treated the value assigned to both strings as a single string literal, and so the string variables refer to the same interned string. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.cs" id="Snippet1"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/RuntimeHelpers/GetHashCode/gethashcodeex1.vb" id="Snippet1"::: + + ]]> + diff --git a/xml/System.Runtime.InteropServices/COMException.xml b/xml/System.Runtime.InteropServices/COMException.xml index ac0c308dba2..f03cd3e9ee8 100644 --- a/xml/System.Runtime.InteropServices/COMException.xml +++ b/xml/System.Runtime.InteropServices/COMException.xml @@ -62,7 +62,34 @@ The exception that is thrown when an unrecognized HRESULT is returned from a COM method call. - For more information about this API, see Supplemental API remarks for COMException. + + class is the exception that's thrown when an unrecognized HRESULT is returned from a COM method call. + +The common language runtime transforms well-known HRESULTs to .NET exceptions, enabling COM objects to return meaningful error information to managed clients. The HRESULT-to-exception mapping also works in the other direction by returning specific HRESULTs to unmanaged clients. For mapping details, see [How to map HRESULTs and exceptions](/dotnet/framework/interop/how-to-map-hresults-and-exceptions). + +When the runtime encounters an unfamiliar HRESULT (an HRESULT that lacks a specific, corresponding exception), it throws an instance of the class. This all-purpose exception exposes the same members as any exception, and inherits a public property that contains the HRESULT returned by the callee. If an error message is available to the runtime (obtained from the [IErrorInfo](/previous-versions/windows/desktop/ms723041(v=vs.85)) interface or the `Err` object in Visual Basic, or in some cases from the operating system), the message is returned to the caller. However, if the COM component developer fails to include an error message, the runtime returns the eight-digit HRESULT in place of a message string. Having an HRESULT allows the caller to determine the cause of the generic exception. + +## Handle a COMException exception + +The following are some considerations for troubleshooting a exception. + +Check the property +When the runtime encounters an unfamiliar HRESULT and throws a exception, the property includes either the error message or, if an error message is unavailable, the eight-digit HRESULT value. The error message or the HRESULT value can help you determine the cause of the exception. + +For a list of HRESULT values, see [Common HRESULT Values](/windows/win32/seccrypto/common-hresult-values). + +When passing late-bound arguments to methods of Microsoft Office objects, a exception may be thrown when the objects are COM objects. The late binder assumes that such method calls involve a `ByRef` parameter and that the property you pass has a `set` accessor. If the property does not, .NET generates a exception (with a `CORE_E_MISSINGMETHOD` HRESULT ). To work around this behavior, use early-bound objects or pass a variable instead of a property of the object. + +COM is used to communicate between Visual Studio and the [hosting process](/visualstudio/ide/hosting-process-vshost-exe?preserve-view=vs-2015). Because it is used before code runs, a call to [CoInitializeSecurity](/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity) causes this exception to be thrown. In some cases, running Visual Studio as Administrator may resolve the issue. You can also [disable the hosting process](/visualstudio/ide/how-to-disable-the-hosting-process?preserve-view=vs-2015). + +## Throw a COMException exception + +Although you can use the class to return specific HRESULTs to unmanaged clients, throwing a specific .NET exception is better than using a generic exception. Consider that managed clients as well as unmanaged clients can use your .NET object, and throwing an HRESULT to a managed caller is less comprehensible than throwing an exception. + + ]]> + Handling and Throwing Exceptions diff --git a/xml/System.Runtime.InteropServices/ComWrappers.xml b/xml/System.Runtime.InteropServices/ComWrappers.xml index 3081a7631af..4afaa0db44d 100644 --- a/xml/System.Runtime.InteropServices/ComWrappers.xml +++ b/xml/System.Runtime.InteropServices/ComWrappers.xml @@ -51,7 +51,60 @@ Class for managing wrappers of COM IUnknown types. - For more information about this API, see Supplemental API remarks for ComWrappers. + + API provides support for the `IUnknown` API independent of the built-in COM interoperability support. The `ComWrappers` API exposes the minimal runtime support that's needed for developers to replace the built-in version in an efficient manner. + +Traditionally in the runtime, a native proxy to managed object is called a COM Callable Wrapper (CCW), and a managed proxy to a native object is called a Runtime Callable Wrapper (RCW). However, when used here, those terms should not be confused with the built-in features of the same name (that is, [CCW](/dotnet/standard/native-interop/com-callable-wrapper) and [RCW](/dotnet/standard/native-interop/runtime-callable-wrapper)). Unlike the built-in features, a majority of the responsibility for accurate lifetime management, dispatching methods, and marshalling of arguments and return values is left to the `ComWrappers` implementer. + +"Minimal support" is defined by the following features: + +1. Efficient mapping between a managed object and a native proxy (for example, CCW). +2. Efficient mapping between a native `IUnknown` and its managed proxy (for example, RCW). +3. Integration with the garbage collector through the [IReferenceTrackerHost](/windows/win32/api/windows.ui.xaml.hosting.referencetracker/nn-windows-ui-xaml-hosting-referencetracker-ireferencetrackerhost) interface contract. + +Leveraging this is an advanced scenario. + +## Proxy state + +This section provides descriptions and illustrations of native and managed proxy state after their respective creation. + +In the following illustrations, a strong reference is depicted as a solid line (`===`) and a weak reference is depicted as a dashed line (`= = =`). The terms "strong reference" and "weak reference" should be interpreted as "extending lifetime" and "not extending lifetime", as opposed to implying a specific implementation. + +The following illustration shows the state of the managed object and native proxy after a call to . + +``` + -------------------- ---------------------- +| Managed object | | Native proxy | +| | | Ref count: 1 | +| ---------------- | | ------------------ | +| | Weak reference |=| = = = = = = = >| | Strong reference | | +| | to proxy | |<===============|=| to object | | +| ---------------- | | ------------------ | + -------------------- ---------------------- +``` + +The next illustration shows the state of the native object and managed proxy after a call to . The concept of "identity" follows the [rules for `IUnknown`](/windows/win32/com/rules-for-implementing-queryinterface#objects-must-have-identity). + +``` + ------------------ ------------------ +| Native object |< = = = = = =| | +| Ref count: +1 | | Mapping from | + ------------------ | native identity | + ------------------------ | to managed proxy | +| Managed proxy |< = = =| | +| Created by ComWrappers | ------------------ +| implementer. | +| Optional AddRef() on | +| native object. | + ------------------------ +``` + +Observe that only weak references exist from the runtime perspective. The `+1` reference count on the native object is assumed to be performed by the managed proxy creator (that is, the `ComWrappers` implementer) to ensure the associated lifetime between the native object and its managed proxy. There is an optional strong reference (that is, `AddRef()`) mentioned in the managed proxy, which is used to support scenario (3) mentioned earlier. See . With this optional strong reference, the reference count would be `+2`. + + ]]> + diff --git a/xml/System.Runtime.InteropServices/ICustomMarshaler.xml b/xml/System.Runtime.InteropServices/ICustomMarshaler.xml index 4ffad6462e1..2641447ee1d 100644 --- a/xml/System.Runtime.InteropServices/ICustomMarshaler.xml +++ b/xml/System.Runtime.InteropServices/ICustomMarshaler.xml @@ -43,7 +43,154 @@ Provides custom wrappers for handling method calls. - For more information about this API, see Supplemental API remarks for ICustomMarshaler. + + interface provides custom wrappers for handling method calls. + +A marshaller provides a bridge between the functionality of old and new interfaces. Custom marshaling provides the following benefits: + +- It enables client applications that were designed to work with an old interface to also work with servers that implement a new interface. +- It enables client applications built to work with a new interface to work with servers that implement an old interface. + +If you have an interface that introduces different marshaling behavior or that is exposed to the Component Object Model (COM) in a different way, you can design a custom marshaller instead of using the interop marshaller. By using a custom marshaller, you can minimize the distinction between new .NET Framework components and existing COM components. + +For example, suppose that you are developing a managed interface called `INew`. When this interface is exposed to COM through a standard COM callable wrapper (CCW), it has the same methods as the managed interface and uses the marshaling rules built into the interop marshaller. Now suppose that a well-known COM interface called `IOld` already provides the same functionality as the `INew` interface. By designing a custom marshaller, you can provide an unmanaged implementation of `IOld` that simply delegates the calls to the managed implementation of the `INew` interface. Therefore, the custom marshaller acts as a bridge between the managed and unmanaged interfaces. + +> [!NOTE] +> Custom marshallers are not invoked when calling from managed code to unmanaged code on a dispatch-only interface. + +## Define the marshaling type + +Before you can build a custom marshaller, you must define the managed and unmanaged interfaces that will be marshaled. These interfaces commonly perform the same function but are exposed differently to managed and unmanaged objects. + +A managed compiler produces a managed interface from metadata, and the resulting interface looks like any other managed interface. The following example shows a typical interface. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet1"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb" id="Snippet1"::: + +You define the unmanaged type in Interface Definition Language (IDL) and compile it with the Microsoft Interface Definition Language (MIDL) compiler. You define the interface within a library statement and assign it an interface ID with the universal unique identifier (UUID) attribute, as the following example demonstrates. + +``` + [uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)] +library OldLib { + [uuid(9B2BAADD-0705-11D3-A0CD-00C04FA35826)] + interface IOld : IUnknown + HRESULT OldMethod(); +} +``` + +The MIDL compiler produces several output files. If the interface is defined in Old.idl, the output file Old_i.c defines a `const` variable with the interface identifier (IID) of the interface, as the following example demonstrates. + +``` +const IID IID_IOld = {0x9B2BAADD,0x0705,0x11D3,{0xA0,0xCD,0x00,0xC0,0x4F,0xA3,0x58,0x26}}; +``` + +The Old.h file is also produced by MIDL. It contains a C++ definition of the interface that can be included in your C++ source code. + +## Implement the ICustomMarshaler interface + +Your custom marshaller must implement the interface to provide the appropriate wrappers to the runtime. + +The following C# code displays the base interface that must be implemented by all custom marshallers. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet2"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb" id="Snippet2"::: + +The interface includes methods that provide conversion support, cleanup support, and information about the data to be marshaled. + +|Type of operation|ICustomMarshaler method|Description| +|-----------------------|-----------------------------|-----------------| +|Conversion (from native to managed code)||Marshals a pointer to native data into a managed object. This method returns a custom runtime callable wrapper (RCW) that can marshal the unmanaged interface that is passed as an argument. The marshaller should return an instance of the custom RCW for that type.| +|Conversion (from managed to native code)||Marshals a managed object into a pointer to native data. This method returns a custom COM callable wrapper (CCW) that can marshal the managed interface that is passed as an argument. The marshaller should return an instance of the custom CCW for that type.| +|Cleanup (of native code)||Enables the marshaller to clean up the native data (the CCW) that is returned by the method.| +|Cleanup (of managed code)||Enables the marshaller to clean up the managed data (the RCW) that is returned by the method.| +|Information (about native code)||Returns the size of the unmanaged data to be marshaled.| + +### Conversion + + + +Marshals a pointer to native data into a managed object. This method returns a custom runtime callable wrapper (RCW) that can marshal the unmanaged interface that is passed as an argument. The marshaller should return an instance of the custom RCW for that type. + + + +Marshals a managed object into a pointer to native data. This method returns a custom COM callable wrapper (CCW) that can marshal the managed interface that is passed as an argument. The marshaller should return an instance of the custom CCW for that type. + +### Cleanup + + + +Enables the marshaller to clean up the native data (the CCW) that is returned by the method. + + + +Enables the marshaller to clean up the managed data (the RCW) that is returned by the method. + +### Size information + + + +Returns the size of the unmanaged data to be marshaled. + +> [!NOTE] +> If a custom marshaller calls any methods that set the last P/Invoke error when marshaling from native to managed or when cleaning up, the value returned by and will represent the call in the marshaling or cleanup calls. This can cause errors to be missed when using custom marshallers with P/Invokes with set to `true`. To preserve the last P/Invoke error, use the and methods in the implementation. + +## Implement the GetInstance method + +In addition to implementing the interface, custom marshallers must implement a `static` method called `GetInstance` that accepts a as a parameter and has a return type of . This `static` method is called by the common language runtime's COM interop layer to instantiate an instance of the custom marshaller. The string that is passed to `GetInstance` is a cookie that the method can use to customize the returned custom marshaller. The following example shows a minimal, but complete, implementation. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet6"::: + +## Apply MarshalAsAttribute + +To use a custom marshaller, you must apply the attribute to the parameter or field that is being marshaled. + +You must also pass the enumeration value to the constructor. In addition, you must specify the field with one of the following named parameters: + +- (required): The assembly-qualified name of the custom marshaller. The name should include the namespace and class of the custom marshaller. If the custom marshaller is not defined in the assembly it is used in, you must specify the name of the assembly in which it is defined. + + > [!NOTE] + > You can use the field instead of the field. takes a type that is easier to specify. + +- (optional): A cookie that is passed to the custom marshaller. You can use the cookie to provide additional information to the marshaller. For example, if the same marshaller is used to provide a number of wrappers, the cookie identifies a specific wrapper. The cookie is passed to the `GetInstance` method of the marshaller. + +The attribute identifies the custom marshaller so it can activate the appropriate wrapper. The common language runtime's interop service then examines the attribute and creates the custom marshaller the first time the argument (parameter or field) needs to be marshaled. + +The runtime then calls the and methods on the custom marshaller to activate the correct wrapper to handle the call. + +## Use a custom marshaller + +When the custom marshaller is complete, you can use it as a custom wrapper for a particular type. The following example shows the definition of the `IUserData` managed interface: + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet3"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb" id="Snippet3"::: + +In the following example, the `IUserData` interface uses the `NewOldMarshaler` custom marshaller to enable unmanaged client applications to pass an `IOld` interface to the `DoSomeStuff` method. The managed description of the `DoSomeStuff` method takes an `INew` interface, as shown in the previous example, whereas the unmanaged version of `DoSomeStuff` takes an `IOld` interface pointer, as shown in the following example. + +``` +[uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)] +library UserLib { + [uuid(9B2BABCD-0705-11D3-A0CD-00C04FA35826)] + interface IUserData : IUnknown + HRESULT DoSomeStuff(IUnknown* pIOld); +} +``` + +The type library that is generated by exporting the managed definition of `IUserData` yields the unmanaged definition shown in this example instead of the standard definition. The attribute applied to the `INew` argument in the managed definition of the `DoSomeStuff` method indicates that the argument uses a custom marshaller, as the following example shows. + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet4"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb" id="Snippet4"::: + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.cs" id="Snippet5"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.InteropServices/ICustomMarshaler/Overview/source.vb" id="Snippet5"::: + +In the previous examples, the first parameter provided to the attribute is the enumeration value `UnmanagedType.CustomMarshaler`. + +The second parameter is the field, which provides the assembly-qualified name of the custom marshaller. This name consists of the namespace and class of the custom marshaller (`MarshalType="MyCompany.NewOldMarshaler"`). + + ]]> + diff --git a/xml/System.Runtime.InteropServices/SafeHandle.xml b/xml/System.Runtime.InteropServices/SafeHandle.xml index bc99b8c4786..dd7f513641c 100644 --- a/xml/System.Runtime.InteropServices/SafeHandle.xml +++ b/xml/System.Runtime.InteropServices/SafeHandle.xml @@ -91,7 +91,42 @@ Represents a wrapper class for operating system handles. This class must be inherited. - For more information about this API, see Supplemental API remarks for SafeHandle. + + class provides critical finalization of handle resources, preventing handles from being reclaimed prematurely by garbage collection and from being recycled by the operating system to reference unintended unmanaged objects. + +## Why SafeHandle? + +Although overrides to the method allow cleanup of unmanaged resources when an object is being garbage collected, in some circumstances, finalizable objects can be reclaimed by garbage collection while executing a method within a platform invoke call. If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file. + +More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. This is known as a recycle attack and can potentially corrupt data and be a security threat. + +## What SafeHandle does + +The class simplifies several of these object lifetime issues, and is integrated with platform invoke so that operating system resources are not leaked. The class resolves object lifetime issues by assigning and releasing handles without interruption. It contains a critical finalizer that ensures that the handle is closed and is guaranteed to run during unexpected unloads, even in cases when the platform invoke call is assumed to be in a corrupted state. + +Because inherits from , all the noncritical finalizers are called before any of the critical finalizers. The finalizers are called on objects that are no longer live during the same garbage collection pass. For example, a object can run a normal finalizer to flush out existing buffered data without the risk of the handle being leaked or recycled. This very weak ordering between critical and noncritical finalizers is not intended for general use. It exists primarily to assist in the migration of existing libraries by allowing those libraries to use without altering their semantics. Additionally, the critical finalizer and anything it calls, such as the method, must be in a constrained execution region. This imposes constraints on what code can be written within the finalizer's call graph. + +Platform invoke operations automatically increment the reference count of handles encapsulated by a and decrement them upon completion. This ensures that the handle will not be recycled or closed unexpectedly. + +You can specify ownership of the underlying handle when constructing objects by supplying a value to the `ownsHandle` argument in the class constructor. This controls whether the object will release the handle after the object has been disposed. This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else. + +## Classes derived from SafeHandle + + is an abstract wrapper class for operating system handles. Deriving from this class is difficult. Instead, use the derived classes in the namespace that provide safe handles for the following: + +- Files (the class). +- Memory mapped files (the class). +- Pipes (the class). +- Memory views (the class). +- Cryptography constructs (the , , , and classes). +- Processes (the class). +- Registry keys (the class). +- Wait handles (the class). + + ]]> + . It reads bytes from a file and displays their hexadecimal values. It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. When using an to represent handles, the handle is occasionally leaked due to the asynchronous thread abort. diff --git a/xml/System.Runtime.Loader/AssemblyLoadContext.xml b/xml/System.Runtime.Loader/AssemblyLoadContext.xml index d0e0e9a716a..82fab39f5b9 100644 --- a/xml/System.Runtime.Loader/AssemblyLoadContext.xml +++ b/xml/System.Runtime.Loader/AssemblyLoadContext.xml @@ -40,7 +40,61 @@ Represents the runtime's concept of a scope for assembly loading. - For more information about this API, see Supplemental API remarks for AssemblyLoadContext. + + represents a load context. Conceptually, a load context creates a scope for loading, resolving, and potentially unloading a set of assemblies. + +The exists primarily to provide assembly loading isolation. It allows multiple versions of the same assembly to be loaded within a single process. It replaces the isolation mechanisms provided by multiple instances in .NET Framework. + +> [!NOTE] +> +> * does not provide any security features. All code has full permissions of the process. +> * In .NET Core 2.0 - 2.2 only, is an abstract class. To create a concrete class in these versions, implement the method. + +## Usage in the runtime + +The runtime implements two assembly load contexts: + +* represents the runtime's default context, which is used for the application main assembly and its static dependencies. +* The method isolates the assemblies it loads by instantiating the most basic . It has a simplistic isolation scheme that loads each assembly in its own with no dependency resolution. + +### Application usage + +An application can create its own to create a custom solution for advanced scenarios. The customization focuses on defining dependency resolution mechanisms. + +The provides two extension points to implement managed assembly resolution: + +1. The method provides the first chance for the to resolve, load, and return the assembly. If the method returns `null`, the loader tries to load the assembly into the . +2. If the is unable to resolve the assembly, the original gets a second chance to resolve the assembly. The runtime raises the event. + +Additionally, the virtual method allows customization of the default unmanaged assembly resolution. The default implementation returns `null`, which causes the runtime search to use its default search policy. The default search policy is sufficient for most scenarios. + +## Technical challenges + +* It's not possible to load multiple versions of the runtime in a single process. + + > [!CAUTION] + > Loading multiple copies or different versions of framework assemblies can lead to unexpected and hard-to-diagnose behavior. + + > [!TIP] + > Use process boundaries with remoting or interprocess communication to solve this isolation problem. + +* The timing of assembly loading can make testing and debugging difficult. Assemblies are typically loaded without their dependencies immediately being resolved. The dependencies are loaded as they are needed: + + * When code branches into a dependent assembly. + * When code loads resources. + * When code explicitly loads assemblies. + +* The implementation of can add new dependencies that may need to be isolated to allow different versions to exist. The most natural implementation would place these dependencies in the default context. Careful design can isolate the new dependencies. + +* The same assembly is loaded multiple times into different contexts. + + * This can lead to confusing error messages, for example "Unable to cast object of type 'Sample.Plugin' to type 'Sample.Plugin'". + * Marshaling across isolation boundaries is non-trivial. A typical solution is to use an interface defined in an assembly that's only loaded into the default load context. + + ]]> + About AssemblyLoadContext How to use and debug assembly unloadability AssemblyLoadContext CoreCLR design document diff --git a/xml/System.Runtime.Serialization/DataContractAttribute.xml b/xml/System.Runtime.Serialization/DataContractAttribute.xml index d6a5ff76734..89ea35df2fc 100644 --- a/xml/System.Runtime.Serialization/DataContractAttribute.xml +++ b/xml/System.Runtime.Serialization/DataContractAttribute.xml @@ -56,7 +56,48 @@ Specifies that the type defines or implements a data contract and is serializable by a serializer, such as the . To make their type serializable, type authors must define a data contract for their type. - For more information about this API, see Supplemental API remarks for DataContractAttribute. + + attribute to types (classes, structures, or enumerations) that are used in serialization and deserialization operations by the . If you send or receive messages by using the Windows Communication Foundation (WCF) infrastructure, you should also apply the to any classes that hold and manipulate data sent in messages. For more information about data contracts, see [Using Data Contracts](/dotnet/framework/wcf/feature-details/using-data-contracts). + +You must also apply the to any field, property, or event that holds values you want to serialize. By applying the , you explicitly enable the to serialize and deserialize the data. + +> [!CAUTION] +> You can apply the to private fields. Be aware that the data returned by the field (even if it is private) is serialized and deserialized, and thus can be viewed or intercepted by a malicious user or process. + +For more information about data contracts, see the topics listed in [Using Data Contracts](/dotnet/framework/wcf/feature-details/using-data-contracts). + +## Data contracts + +A *data contract* is an abstract description of a set of fields with a name and data type for each field. The data contract exists outside of any single implementation to allow services on different platforms to interoperate. As long as the data passed between the services conforms to the same contract, all the services can process the data. This processing is also known as a *loosely coupled system*. A data contract is also similar to an interface in that the contract specifies how data must be delivered so that it can be processed by an application. For example, the data contract may call for a data type named "Person" that has two text fields, named "FirstName" and "LastName". To create a data contract, apply the to the class and apply the to any fields or properties that must be serialized. When serialized, the data conforms to the data contract that is implicitly built into the type. + +> [!NOTE] +> A data contract differs significantly from an actual interface in its inheritance behavior. Interfaces are inherited by any derived types. When you apply the to a base class, the derived types do not inherit the attribute or the behavior. However, if a derived type has a data contract, the data members of the base class are serialized. However, you must apply the to new members in a derived class to make them serializable. + +## XML schema documents and the SvcUtil tool + +If you are exchanging data with other services, you must describe the data contract. For the current version of the , an XML schema can be used to define data contracts. (Other forms of metadata/description could be used for the same purpose.) To create an XML schema from your application, use the [ServiceModel Metadata Utility Tool (Svcutil.exe)](/dotnet/framework/wcf/servicemodel-metadata-utility-tool-svcutil-exe) with the **/dconly** command line option. When the input to the tool is an assembly, by default, the tool generates a set of XML schemas that define all the data contract types found in that assembly. Conversely, you can also use the Svcutil.exe tool to create Visual Basic or C# class definitions that conform to the requirements of XML schemas that use constructs that can be expressed by data contracts. In this case, the **/dconly** command line option is not required. + +If the input to the Svcutil.exe tool is an XML schema, by default, the tool creates a set of classes. If you examine those classes, you find that the has been applied. You can use those classes to create a new application to process data that must be exchanged with other services. + +You can also run the tool against an endpoint that returns a Web Services Description Language (WSDL) document to automatically generate the code and configuration to create an Windows Communication Foundation (WCF) client. The generated code includes types that are marked with the . + +## Reuse existing types + +A data contract has two basic requirements: a stable name and a list of members. The stable name consists of the namespace uniform resource identifier (URI) and the local name of the contract. By default, when you apply the to a class, it uses the class name as the local name and the class's namespace (prefixed with `"http://schemas.datacontract.org/2004/07/"`) as the namespace URI. You can override the defaults by setting the and properties. You can also change the namespace by applying the to the namespace. Use this capability when you have an existing type that processes data exactly as you require but has a different namespace and class name from the data contract. By overriding the default values, you can reuse your existing type and have the serialized data conform to the data contract. + +> [!NOTE] +> In any code, you can use the word `DataContract` instead of the longer . + +## Versioning + +A data contract can also accommodate later versions of itself. That is, when a later version of the contract includes extra data, that data is stored and returned to a sender untouched. To do this, implement the interface. + +For more information about versioning, see [Data Contract Versioning](/dotnet/framework/wcf/feature-details/data-contract-versioning). + + ]]> + has been applied. Note that the and properties have been set to values that override the default settings. diff --git a/xml/System.Runtime.Serialization/DataContractSerializer.xml b/xml/System.Runtime.Serialization/DataContractSerializer.xml index 48ad11fd00c..80cce00fdd6 100644 --- a/xml/System.Runtime.Serialization/DataContractSerializer.xml +++ b/xml/System.Runtime.Serialization/DataContractSerializer.xml @@ -52,7 +52,52 @@ Serializes and deserializes an instance of a type into an XML stream or document using a supplied data contract. This class cannot be inherited. - For more information about this API, see Supplemental API remarks for DataContractSerializer. + + class to serialize and deserialize instances of a type into an XML stream or document. For example, you can create a type named `Person` with properties that contain essential data, such as a name and address. You can then create and manipulate an instance of the `Person` class and write all of its property values in an XML document for later retrieval, or in an XML stream for immediate transport. Most important, the is used to serialize and deserialize data sent in Windows Communication Foundation (WCF) messages. Apply the attribute to classes, and the attribute to class members to specify properties and fields that are serialized. + +For a list of types that can be serialized, see [Types Supported by the Data Contract Serializer](/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer). + +To use the , first create an instance of a class and an object appropriate to writing or reading the format; for example, an instance of the . Then call the method to persist the data. To retrieve data, create an object appropriate to reading the data format (such as an for an XML document) and call the method. + +For more information about using the , see [Serialization and Deserialization](/dotnet/framework/wcf/feature-details/serialization-and-deserialization). + +You can set the type of a data contract serializer using the [<dataContractSerializer>](/dotnet/framework/configure-apps/file-schema/wcf/datacontractserializer-element) element in a client application configuration file. + +## Prepare classes for serialization or deserialization + +The is used in combination with the and classes. To prepare a class for serialization, apply the to the class. For each member of the class that returns data that you want to serialize, apply the . You can serialize fields and properties, regardless of accessibility: private, protected, internal, protected internal, or public. + +For example, your schema specifies a `Customer` with an `ID` property, but you already have an existing application that uses a type named `Person` with a `Name` property. To create a type that conforms to the contract, first apply the to the class. Then apply the to every field or property that you want to serialize. + +> [!NOTE] +> You can apply the to both private and public members. + +The final format of the XML need not be text. Instead, the writes the data as an XML infoset, which allows you to write the data to any format recognized by the and . It is recommended that you use the and classes to read and write, because both are optimized to work with the . + +If you are creating a class that has fields or properties that must be populated before the serialization or deserialization occurs, use callback attributes, as described in [Version-Tolerant Serialization Callbacks](/dotnet/framework/wcf/feature-details/version-tolerant-serialization-callbacks). + +## Add to the collection of known types + +When serializing or deserializing an object, it is required that the type is "known" to the . Begin by creating an instance of a class that implements (such as ) and adding the known types to the collection. Then create an instance of the using one of the overloads that takes the (for example, ). + +> [!NOTE] +> Unlike other primitive types, the structure is not a known type by default, so it must be manually added to the list of known types (see [Data Contract Known Types](/dotnet/framework/wcf/feature-details/data-contract-known-types)). + +## Forward compatibility + +The understands data contracts that have been designed to be compatible with future versions of the contract. Such types implement the interface. The interface features the property that returns an object. For more information, see [Forward-Compatible Data Contracts](/dotnet/framework/wcf/feature-details/forward-compatible-data-contracts). + +## Run under partial trust + +When instantiating the target object during deserialization, the does not call the constructor of the target object. If you author a *[DataContract]* type that is accessible from partial trust (that is, it is public and in an assembly that has the `AllowPartiallyTrustedCallers` attribute applied) and that performs some security-related actions, you must be aware that the constructor is not called. In particular, the following techniques do not work: + +- If you try to restrict partial trust access by making the constructor internal or private, or by adding a `LinkDemand` to the constructor -- neither of these have any effect during deserialization under partial trust. +- If you code the class that assumes the constructor has run, the class may get into an invalid internal state that is exploitable. + + ]]> + Instances of this class are thread safe except when the instance is used with an implementation of the or . diff --git a/xml/System.Runtime.Serialization/IExtensibleDataObject.xml b/xml/System.Runtime.Serialization/IExtensibleDataObject.xml index 6e34786b784..65265159ea0 100644 --- a/xml/System.Runtime.Serialization/IExtensibleDataObject.xml +++ b/xml/System.Runtime.Serialization/IExtensibleDataObject.xml @@ -42,7 +42,27 @@ Provides a data structure to store extra data encountered by the during deserialization of a type marked with the attribute. - For more information about this API, see Supplemental API remarks for IExtensibleDataObject. + + interface provides a single property that sets or returns a structure used to store data that is external to a data contract. The extra data is stored in an instance of the class and accessed through the property. In a roundtrip operation where data is received, processed, and sent back, the extra data is sent back to the original sender intact. This is useful to store data received from future versions of the contract. If you do not implement the interface, any extra data is ignored and discarded during a roundtrip operation. + +## To use this versioning feature + +1. Implement the interface in a class. + +2. Add the property to your type. + +3. Add a private member of type to the class. + +4. Implement get and set methods for the property using the new private member. + +5. Apply the attribute to the class. Set the and properties to appropriate values if necessary. + +For more information about versioning of types, see [Data Contract Versioning](/dotnet/framework/wcf/feature-details/data-contract-versioning). For information about creating forward-compatible data contracts, see [Forward-Compatible Data Contracts](/dotnet/framework/wcf/feature-details/forward-compatible-data-contracts). For more information about data contracts, see [Using Data Contracts](/dotnet/framework/wcf/feature-details/using-data-contracts). + + ]]> + Allows the transformation of a set of .NET types that are used in data contracts into an XML schema file (.xsd). - For more information about this API, see Supplemental API remarks for XsdDataContractExporter. + + class when you have created a Web service that incorporates data represented by common language runtime (CLR) types and when you need to export XML schemas for each type to be consumed by other Web services. That is, transforms a set of CLR types into XML schemas. (For more information about the types that can be used, see [Types Supported by the Data Contract Serializer](/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer).) The schemas can then be exposed through a Web Services Description Language (WSDL) document for use by others who need to interoperate with your service. + +Conversely, if you are creating a Web service that must interoperate with an existing Web service, use the to transform XML schemas and create the CLR types that represent the data in a selected programming language. + +The generates an object that contains the collection of schemas. Access the set of schemas through the property. + +> [!NOTE] +> To quickly generate XML schema definition (XSD) files that other Web services can consume, use the . + +## Export schemas into an XmlSchemaSet + +To create an instance of the class that contains XML schema files, you should be aware of the following. + +The set of types you are exporting are recorded as an internal set of data contracts. Thus, you can call the method multiple times to add new types to the schema set without degrading performance because only the new types will be added to the set. During the operation, the existing schemas are compared to the new schemas being added. If there are conflicts, an exception will be thrown. A conflict is usually detected if two types with the same data contract name but different contracts (different members) are exported by the same instance. + +## Use the exporter + +A recommended way of using this class is as follows: + +1. Use one of the overloads to determine whether the specified type or set of types can be exported. Use one of the overloads that is appropriate to your requirements. + +2. Call the corresponding method. + +3. Retrieve the schemas from the property. + + ]]> + and calls the method. diff --git a/xml/System.Runtime.Versioning/ComponentGuaranteesAttribute.xml b/xml/System.Runtime.Versioning/ComponentGuaranteesAttribute.xml index 9b2276f7da6..28c6087a3bd 100644 --- a/xml/System.Runtime.Versioning/ComponentGuaranteesAttribute.xml +++ b/xml/System.Runtime.Versioning/ComponentGuaranteesAttribute.xml @@ -59,7 +59,132 @@ Defines the compatibility guarantee of a component, type, or type member that may span multiple versions. - For more information about this API, see Supplemental API remarks for ComponentGuaranteesAttribute. + + is used by developers of components and class libraries to indicate the level of compatibility that consumers of their libraries can expect across multiple versions. It indicates the level of guarantee that a future version of the library or component will not break an existing client. Clients can then use the as an aid in designing their own interfaces to ensure stability across versions. + +> [!NOTE] +> The common language runtime (CLR) does not use this attribute in any way. Its value lies in formally documenting the intent of the component author. Compile-time tools can also use these declarations to detect compile-time errors that would otherwise break the declared guarantee. + +## Levels of compatibility + +The supports the following levels of compatibility, which are represented by members of the enumeration: + +- No version-to-version compatibility (). The client can expect that future versions will break the existing client. For more information, see the [No compatibility](#no-compatibility) section later in this article. + +- Side-by-side version-to-version compatibility (). The component has been tested to work when more than one version of the assembly is loaded in the same application domain. In general, future versions can break compatibility. However, when breaking changes are made, the old version is not modified but exists alongside the new version. Side-by-side execution is the expected way to make existing clients work when breaking changes are made. For more information, see the [Side-by-side compatibility](#side-by-side-compatibility) section later in this article. + +- Stable version-to-version compatibility (). Future versions should not break the client, and side-by-side execution should not be needed. However, if the client is inadvertently broken, it may be possible to use side-by-side execution to fix the problem. For more information, see the [Stable compatibility](#stable-compatibility) section. + +- Exchange version-to-version compatibility (). Extraordinary care is taken to ensure that future versions will not break the client. The client should use only these types in the signature of interfaces that are used for communication with other assemblies that are deployed independently of one another. Only one version of these types is expected to be in a given application domain, which means that if a client breaks, side-by-side execution cannot fix the compatibility problem. For more information, see the [Exchange type compatibility](#exchange-type-compatibility) section. + +The following sections discuss each level of guarantee in greater detail. + +### No compatibility + +Marking a component as indicates that the provider makes no guarantees about compatibility. Clients should avoid taking any dependencies on the exposed interfaces. This level of compatibility is useful for types that are experimental or that are publicly exposed but are intended only for components that are always updated at the same time. explicitly indicates that this component should not be used by external components. + +### Side-by-side compatibility + +Marking a component as indicates that the component has been tested to work when more than one version of the assembly is loaded into the same application domain. Breaking changes are allowed as long as they are made to the assembly that has the greater version number. Components that are bound to an old version of the assembly are expected to continue to bind to the old version, and other components can bind to the new version. It is also possible to update a component that is declared to be by destructively modifying the old version. + +### Stable compatibility + +Marking a type as indicates that the type should remain stable across versions. However, it may also be possible for side-by-side versions of a stable type to exist in the same application domain. + +Stable types maintain a high binary compatibility bar. Because of this, providers should avoid making breaking changes to stable types. The following kinds of changes are acceptable: + +- Adding private instance fields to, or removing fields from, a type, as long as this does not break the serialization format. +- Changing a non-serializable type to a serializable type. (However, a serializable type cannot be changed to a non-serializable type.) +- Throwing new, more derived exceptions from a method. +- Improving the performance of a method. +- Changing the range of return values, as long as the change does not adversely affect the majority of clients. +- Fixing serious bugs, if the business justification is high and the number of adversely affected clients is low. + +Because new versions of stable components are not expected to break existing clients, generally only one version of a stable component is needed in an application domain. However, this is not a requirement, because stable types are not used as well-known exchange types that all components agree upon. Therefore, if a new version of a stable component does inadvertently break some component, and if other components need the new version, it may be possible to fix the problem by loading both the old and new component. + + provides a stronger version compatibility guarantee than . It is a common default for multi-version components. + + can be combined with , which states that the component will not break compatibility but is tested to work when more than one version is loaded in a given application domain. + +After a type or method is marked as , it can be upgraded to . However, it cannot be downgraded to . + +### Exchange type compatibility + +Marking a type as provides a stronger version compatibility guarantee than , and should be applied to the most stable of all types. These types are intended to be used for interchange between independently built components across all component boundaries in both time (any version of the CLR or any version of a component or application) and space (cross-process, cross-CLR in one process, cross-application domain in one CLR). If a breaking change is made to an exchange type, it is impossible to fix the issue by loading multiple versions of the type. + +Exchange types should be changed only when a problem is very serious (such as a severe security issue) or the probability of breakage is very low (that is, if the behavior was already broken in a random way that code could not have conceivably taken a dependency on). You can make the following kinds of changes to an exchange type: + +- Add inheritance of new interface definitions. + +- Add new private methods that implement the methods of newly inherited interface definitions. + +- Add new static fields. + +- Add new static methods. + +- Add new non-virtual instance methods. + +The following are considered breaking changes and are not allowed for primitive types: + +- Changing serialization formats. Version-tolerant serialization is required. + +- Adding or removing private instance fields. This risks changing the serialization format of the type and breaking client code that uses reflection. + +- Changing the serializability of a type. A non-serializable type may not be made serializable, and vice versa. + +- Throwing different exceptions from a method. + +- Changing the range of a method's return values, unless the member definition raises this possibility and clearly indicates how clients should handle unknown values. + +- Fixing most bugs. Consumers of the type will rely on the existing behavior. + +After a component, type, or member is marked with the guarantee, it cannot be changed to either or . + +Typically, exchange types are the basic types (such as and in .NET) and interfaces (such as , , and ) that are commonly used in public interfaces. + +Exchange types may publicly expose only other types that are also marked with compatibility. In addition, exchange types cannot depend on the behavior of Windows APIs that are prone to change. + +## Component guarantees + +The following table indicates how a component's characteristics and usage affect its compatibility guarantee. + +|Component characteristics|Exchange|Stable|Side-by-Side|None| +|-------------------------------|--------------|------------|--------------------|----------| +|Can be used in interfaces between components that version independently.|Y|N|N|N| +|Can be used (privately) by an assembly that versions independently.|Y|Y|Y|N| +|Can have multiple versions in a single application domain.|N|Y|Y|Y| +|Can make breaking changes|N|N|Y|Y| +|Tested to make certain multiple versions of the assembly can be loaded together.|N|N|Y|N| +|Can make breaking changes in place.|N|N|N|Y| +|Can make very safe non-breaking servicing changes in place.|Y|Y|Y|Y| + +## Apply the attribute + +You can apply the to an assembly, a type, or a type member. Its application is hierarchical. That is, by default, the guarantee defined by the property of the attribute at the assembly level defines the guarantee of all types in the assembly and all members in those types. Similarly, if the guarantee is applied to the type, by default it also applies to each member of the type. + +This inherited guarantee can be overridden by applying the to individual types and type members. However, guarantees that override the default can only weaken the guarantee; they cannot strengthen it. For example, if an assembly is marked with the guarantee, its types and members have no compatibility guarantee, and any other guarantee that is applied to types or members in the assembly is ignored. + +## Test the guarantee + +The property returns a member of the enumeration, which is marked with the attribute. This means that you should test for the flag that you are interested in by masking away potentially unknown flags. For example, the following example tests whether a type is marked as . + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.cs" id="Snippet1"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb" id="Snippet1"::: + +The following example tests whether a type is marked as or . + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.cs" id="Snippet2"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb" id="Snippet2"::: + +The following example tests whether a type is marked as (that is, neither nor ). + +:::code language="csharp" source="~/snippets/csharp/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.cs" id="Snippet3"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.Versioning/ComponentGuaranteesAttribute/Overview/apply1.vb" id="Snippet3"::: + + ]]> + From 95d8eeca385f1e803d1f87102d2acb83368a81bb Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:17:27 -0700 Subject: [PATCH 2/6] fix snippets 5000 errors --- .../{Project.csproj => Friend/Friend2.csproj} | 0 .../Overview/{ => Friend}/assembly1.cs | 0 .../Overview/{ => Friend}/friend1.cs | 2 +- .../Overview/{ => Friend}/friend2.cs | 6 ++--- .../Overview/{ => Friend}/multiple1.cs | 0 .../Overview/{ => Friend}/multiple2.cs | 4 ++-- .../Overview/UtilityLib/UtilityLib.csproj} | 0 .../Overview/{ => UtilityLib}/utilitylib.cs | 0 .../Overview/Friend/Friend2.vbproj | 8 +++++++ .../Overview/{ => Friend}/assembly1.vb | 0 .../Overview/{ => Friend}/friend1.vb | 20 ++++++++-------- .../Overview/Friend/friend2.vb | 13 +++++++++++ .../Overview/{ => Friend}/multiple1.vb | 0 .../Overview/Friend/multiple2.vb | 23 +++++++++++++++++++ .../Overview/{ => UtilityLib}/utilitylib.vb | 0 .../Overview/friend2.vb | 13 ----------- .../Overview/multiple2.vb | 23 ------------------- 17 files changed, 60 insertions(+), 52 deletions(-) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{Project.csproj => Friend/Friend2.csproj} (100%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/assembly1.cs (100%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/friend1.cs (97%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/friend2.cs (59%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/multiple1.cs (100%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/multiple2.cs (95%) rename snippets/{visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj => csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/UtilityLib.csproj} (100%) rename snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => UtilityLib}/utilitylib.cs (100%) create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.vbproj rename snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/assembly1.vb (100%) rename snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/friend1.vb (62%) create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb rename snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => Friend}/multiple1.vb (100%) create mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.vb rename snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/{ => UtilityLib}/utilitylib.vb (100%) delete mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb delete mode 100644 snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.csproj similarity index 100% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.csproj rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.csproj diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.cs similarity index 100% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.cs diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.cs similarity index 97% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.cs index cce729d89c8..9f038bc5c75 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.cs @@ -26,7 +26,7 @@ public static void Main() // C:\Program Files\ // -public class FileUtilities +public class FileUtilities1 { internal static string AppendDirectorySeparator(string dir) { diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs similarity index 59% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs index e922949f1b5..0dcc36b4648 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs @@ -2,12 +2,12 @@ using System; using Utilities.StringUtilities; -public class Example +public class Example1 { public static void Main() { String s = "The Sign of the Four"; - Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)); + //Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)); } } -// \ No newline at end of file +// diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs similarity index 100% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs similarity index 95% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs index 981dd1b35e9..538a4a5209a 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs @@ -8,7 +8,7 @@ namespace Utilities { - public class StringUtilities + public class StringUtilities1 { internal static string ToTitleCase(string value) { @@ -23,4 +23,4 @@ internal static string ToTitleCase(string value) return retval; } } -} \ No newline at end of file +} diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/UtilityLib.csproj similarity index 100% rename from snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Project.vbproj rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/UtilityLib.csproj diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.cs similarity index 100% rename from snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.cs rename to snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.cs diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.vbproj b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.vbproj new file mode 100644 index 00000000000..874c98f3477 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/Friend2.vbproj @@ -0,0 +1,8 @@ + + + + Library + net10.0 + + + diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.vb similarity index 100% rename from snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.vb rename to snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.vb diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.vb similarity index 62% rename from snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.vb rename to snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.vb index 71b4d1625ca..76d52dea962 100644 --- a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.vb +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.vb @@ -17,8 +17,8 @@ Imports System.IO Module Example Public Sub Main() Dim dir As String = "C:\Program Files" - dir = FileUtilities.AppendDirectorySeparator(dir) - Console.WriteLine(dir) + dir = FileUtilities1.AppendDirectorySeparator(dir) + Console.WriteLine(dir) End Sub End Module ' The example displays the following output: @@ -26,12 +26,12 @@ End Module ' -Public Class FileUtilities - Friend Shared Function AppendDirectorySeparator(dir As String) As String - If Not dir.Trim().EndsWith(Path.DirectorySeparatorChar) Then - Return dir.Trim() + Path.DirectorySeparatorChar - Else - Return dir - End If - End Function +Public Class FileUtilities1 + Friend Shared Function AppendDirectorySeparator(dir As String) As String + If Not dir.Trim().EndsWith(Path.DirectorySeparatorChar) Then + Return dir.Trim() + Path.DirectorySeparatorChar + Else + Return dir + End If + End Function End Class diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb new file mode 100644 index 00000000000..3f47e27933e --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb @@ -0,0 +1,13 @@ +' Visual Basic .NET Document +Option Strict On + +' +Imports Utilities.StringUtilities + +Module Example1 + Public Sub Main() + Dim s As String = "The Sign of the Four" + ' Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)) + End Sub +End Module +' diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.vb similarity index 100% rename from snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb rename to snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.vb diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.vb new file mode 100644 index 00000000000..6a57dce3423 --- /dev/null +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.vb @@ -0,0 +1,23 @@ +Imports System.Runtime.CompilerServices + +' + +' +Namespace Utilities + Public Class StringUtilities1 + Friend Shared Function ToTitleCase(value As String) As String + Dim retval As String = Nothing + For ctr As Integer = 0 To value.Length - 1 + If ctr = 0 Then + retval += Char.ToUpper(value(ctr)) + ElseIf ctr > 0 AndAlso Char.IsWhiteSpace(value(ctr - 1)) Then + retval += Char.ToUpper(value(ctr)) + Else + retval += value(ctr) + End If + Next + Return retval + End Function + End Class +End Namespace diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.vb similarity index 100% rename from snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.vb rename to snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.vb diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb deleted file mode 100644 index c0e240c8543..00000000000 --- a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb +++ /dev/null @@ -1,13 +0,0 @@ -' Visual Basic .NET Document -Option Strict On - -' -Imports Utilities.StringUtilities - -Module Example - Public Sub Main() - Dim s As String = "The Sign of the Four" - Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)) - End Sub -End Module -' diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb deleted file mode 100644 index 54c1b82611a..00000000000 --- a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb +++ /dev/null @@ -1,23 +0,0 @@ -Imports System.Runtime.CompilerServices - -' - -' -Namespace Utilities - Public Class StringUtilities - Shared Friend Function ToTitleCase(value As String) As String - Dim retval As String = Nothing - For ctr As Integer = 0 To value.Length - 1 - If ctr = 0 Then - retval += Char.ToUpper(value(ctr)) - ElseIf ctr > 0 AndAlso Char.IsWhiteSpace(value(ctr - 1)) - retval += Char.ToUpper(value(ctr)) - Else - retval += value(ctr) - End If - Next - Return retval - End Function - End Class -End Namespace \ No newline at end of file From 9556e667cb2fb774b4917768b46669a622c1281e Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:19:53 -0700 Subject: [PATCH 3/6] fix compile errors --- .../InternalsVisibleToAttribute.xml | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml index 3dbede95aee..9c1ff60cd32 100644 --- a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml +++ b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml @@ -72,13 +72,13 @@ The attribute The attribute is applied at the assembly level. This means that it can be included at the beginning of a source code file, or it can be included in the AssemblyInfo file in a Visual Studio project. You can use the attribute to specify a single friend assembly that can access the internal types and members of the current assembly. You can define multiple friend assemblies in two ways. They can appear as individual assembly-level attributes, as the following example illustrates. -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.cs" id="Snippet3"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple1.vb" id="Snippet3"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs" id="Snippet3"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.vb" id="Snippet3"::: They can also appear with separate tags but a single `assembly` keyword, as the following example illustrates. -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.cs" id="Snippet4"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/multiple2.vb" id="Snippet4"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs" id="Snippet4"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.vb" id="Snippet4"::: The friend assembly is identified by the constructor. Both the current assembly and the friend assembly must be unsigned, or both assemblies must be signed with a strong name. @@ -116,29 +116,30 @@ In C++, in order to make the internal members enabled by the attribute to make an `internal` method named `AppendDirectorySeparator` in a signed assembly visible to another signed assembly. It defines a `FileUtilities` class that includes an internal `AppendDirectorySeparator` method. The attribute is applied to the assembly that contains the `FileUtilities` class. The attribute allows an assembly named `Friend1` to access this internal member. -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.cs" id="Snippet1"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.vb" id="Snippet1"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.cs" id="Snippet1"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.vb" id="Snippet1"::: If the following example is compiled into a strong-named assembly named `Friend1`, the `Example.Main` method in `Friend1` can successfully call the `FileUtilities.AppendDirectorySeparator` method, although the method is internal to the `Assembly1` assembly. If you're compiling in C# from the command line, you must use the **/out** compiler switch to ensure that the name of the friend assembly is available when the compiler binds to external references. -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.cs" id="Snippet2"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.vb" id="Snippet2"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.cs" id="Snippet2"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.vb" id="Snippet2"::: **Unsigned assemblies** The following example uses the attribute to make an `internal` member of an unsigned assembly visible to another unsigned assembly. The attribute ensures that the `internal` `StringLib.IsFirstLetterUpperCase` method in an assembly named `UtilityLib` is visible to the code in an assembly named `Friend2`. The following is the source code for UtilityLib.dll: -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.cs" id="Snippet5"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.vb" id="Snippet5"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.cs" id="Snippet5"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.vb" id="Snippet5"::: The following example provides the source code for the `Friend2` assembly. Note that if you are compiling in C# from the command line, you must use the **/out** compiler switch to ensure that the name of the friend assembly is available when the compiler binds to external references. -:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.cs" id="Snippet6"::: -:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb" id="Snippet6"::: +:::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs" id="Snippet6"::: +:::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb" id="Snippet6"::: ]]> @@ -216,25 +217,25 @@ The following example provides the source code for the `Friend2` assembly. Note The following example uses the attribute to make an `internal` method named `AppendDirectorySeparator` in a signed assembly visible to another signed assembly. It defines a `FileUtilities` class that includes an internal `AppendDirectorySeparator` method. The attribute is applied to the assembly that contains the `FileUtilities` class. The attribute allows an assembly named `Friend1` to access this internal member. - :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.cs" id="Snippet1"::: - :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/assembly1.vb" id="Snippet1"::: + :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.cs" id="Snippet1"::: + :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/assembly1.vb" id="Snippet1"::: If the following example is compiled into a strong-named assembly named `Friend1`, it can successfully call the `FileUtilities.AppendDirectorySeparator` method, even though the method is internal to the `Assembly1` assembly. Note that if you are compiling in C# from the command line, you must use the **/out** compiler switch to ensure that the name of the friend assembly is available when the compiler binds to external references. - :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.cs" id="Snippet2"::: - :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend1.vb" id="Snippet2"::: + :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.cs" id="Snippet2"::: + :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend1.vb" id="Snippet2"::: The following example uses the attribute to make an `internal` member of an unsigned assembly visible to another unsigned assembly. The attribute ensures that the `internal` `StringLib.IsFirstLetterUpperCase` method in an assembly named `UtilityLib` is visible to the code in an assembly named `Friend2`. The following is the source code for UtilityLib.dll: - :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.cs" id="Snippet5"::: - :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/utilitylib.vb" id="Snippet5"::: + :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.cs" id="Snippet5"::: + :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/UtilityLib/utilitylib.vb" id="Snippet5"::: **Unsigned assemblies** The following example provides the source code for the `Friend2` assembly. Note that if you are compiling in C# from the command line, you must use the **/out** compiler switch to ensure that the name of the friend assembly is available when the compiler binds to external references. - :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.cs" id="Snippet6"::: - :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/friend2.vb" id="Snippet6"::: + :::code language="csharp" source="~/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs" id="Snippet6"::: + :::code language="vb" source="~/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb" id="Snippet6"::: ]]> From 4bb99dd6a6bad529e9219d819f939de69d104547 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:28:16 -0700 Subject: [PATCH 4/6] fix compile errors --- .../InternalsVisibleToAttribute/Overview/Friend/friend2.cs | 4 +--- .../InternalsVisibleToAttribute/Overview/Friend/friend2.vb | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs index 0dcc36b4648..c614c641273 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs @@ -1,13 +1,11 @@ // -using System; -using Utilities.StringUtilities; public class Example1 { public static void Main() { String s = "The Sign of the Four"; - //Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)); + //Console.WriteLine(Utilities.StringUtilities.StringLib.IsFirstLetterUpperCase(s)); } } // diff --git a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb index 3f47e27933e..43e8a9a6f14 100644 --- a/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb +++ b/snippets/visualbasic/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.vb @@ -2,12 +2,10 @@ Option Strict On ' -Imports Utilities.StringUtilities - Module Example1 Public Sub Main() Dim s As String = "The Sign of the Four" - ' Console.WriteLine(StringLib.IsFirstLetterUpperCase(s)) + ' Console.WriteLine(Utilities.StringUtilities.StringLib.IsFirstLetterUpperCase(s)) End Sub End Module ' From a600453ef43c9f6cc41da59572fdba585ccfb389 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:59:36 -0700 Subject: [PATCH 5/6] fix errors --- .../InternalsVisibleToAttribute/Overview/Friend/friend2.cs | 1 + .../InternalsVisibleToAttribute.xml | 2 +- xml/System.Runtime.InteropServices/ICustomMarshaler.xml | 2 +- .../DataContractSerializer.xml | 7 ------- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs index c614c641273..636f550ee7b 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/friend2.cs @@ -1,4 +1,5 @@ // +using System; public class Example1 { diff --git a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml index 9c1ff60cd32..ba5c1216f44 100644 --- a/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml +++ b/xml/System.Runtime.CompilerServices/InternalsVisibleToAttribute.xml @@ -63,7 +63,7 @@ The attribute specifies that types that are ordinarily visible only within the current assembly are visible to a specified assembly. -Ordinarily, types and members with [`internal` scope in C#](/dotnet/csharp/language-reference/keywords/internal) or [`Friend` scope in Visual Basic](/dotnet/visual-basic/language-reference/modifiers/friend) are visible only in the assembly in which they are defined. Types and members with [`protected internal`](/dotnet/csharp/language-reference/keywords/protected-internal) scope ([`Protected Friend`](/dotnet/visual-basic/language-reference/modifiers/protected-friend) scope in Visual Basic) are visible only in their own assembly or to types that derive from their containing class. Types and members with [`private protected`](/dotnet/csharp/language-reference/keywords/private-protected) scope ([`Private Protected`](/dotnet/visual-basic/language-reference/modifiers/private-protected) scope in Visual Basic) are visible in the containing class or in types that derive from their containing class within the current assembly +Ordinarily, types and members with [`internal` scope in C#](/dotnet/csharp/language-reference/keywords/internal) or [`Friend` scope in Visual Basic](/dotnet/visual-basic/language-reference/modifiers/friend) are visible only in the assembly in which they are defined. Types and members with [`protected internal`](/dotnet/csharp/language-reference/keywords/protected-internal) scope ([`Protected Friend`](/dotnet/visual-basic/language-reference/modifiers/protected-friend) scope in Visual Basic) are visible only in their own assembly or to types that derive from their containing class. Types and members with [`private protected`](/dotnet/csharp/language-reference/keywords/private-protected) scope ([`Private Protected`](/dotnet/visual-basic/language-reference/modifiers/private-protected) scope in Visual Basic) are visible in the containing class or in types that derive from their containing class within the current assembly. The attribute makes these types and members also visible to the types in a specified assembly, which is known as a friend assembly. This applies only to `internal` (`Friend` in Visual Basic), `protected internal`(`Protected Friend` in Visual Basic), and `private protected` (`Private Protected` in Visual Basic) members, but not `private` ones. diff --git a/xml/System.Runtime.InteropServices/ICustomMarshaler.xml b/xml/System.Runtime.InteropServices/ICustomMarshaler.xml index 2641447ee1d..9274aae2327 100644 --- a/xml/System.Runtime.InteropServices/ICustomMarshaler.xml +++ b/xml/System.Runtime.InteropServices/ICustomMarshaler.xml @@ -53,7 +53,7 @@ A marshaller provides a bridge between the functionality of old and new interfac - It enables client applications that were designed to work with an old interface to also work with servers that implement a new interface. - It enables client applications built to work with a new interface to work with servers that implement an old interface. -If you have an interface that introduces different marshaling behavior or that is exposed to the Component Object Model (COM) in a different way, you can design a custom marshaller instead of using the interop marshaller. By using a custom marshaller, you can minimize the distinction between new .NET Framework components and existing COM components. +If you have an interface that introduces different marshaling behavior or that is exposed to the Component Object Model (COM) in a different way, you can design a custom marshaller instead of using the interop marshaller. By using a custom marshaller, you can minimize the distinction between new .NET components and existing COM components. For example, suppose that you are developing a managed interface called `INew`. When this interface is exposed to COM through a standard COM callable wrapper (CCW), it has the same methods as the managed interface and uses the marshaling rules built into the interop marshaller. Now suppose that a well-known COM interface called `IOld` already provides the same functionality as the `INew` interface. By designing a custom marshaller, you can provide an unmanaged implementation of `IOld` that simply delegates the calls to the managed implementation of the `INew` interface. Therefore, the custom marshaller acts as a bridge between the managed and unmanaged interfaces. diff --git a/xml/System.Runtime.Serialization/DataContractSerializer.xml b/xml/System.Runtime.Serialization/DataContractSerializer.xml index 80cce00fdd6..05f0567db96 100644 --- a/xml/System.Runtime.Serialization/DataContractSerializer.xml +++ b/xml/System.Runtime.Serialization/DataContractSerializer.xml @@ -89,13 +89,6 @@ When serializing or deserializing an object, it is required that the type is "kn The understands data contracts that have been designed to be compatible with future versions of the contract. Such types implement the interface. The interface features the property that returns an object. For more information, see [Forward-Compatible Data Contracts](/dotnet/framework/wcf/feature-details/forward-compatible-data-contracts). -## Run under partial trust - -When instantiating the target object during deserialization, the does not call the constructor of the target object. If you author a *[DataContract]* type that is accessible from partial trust (that is, it is public and in an assembly that has the `AllowPartiallyTrustedCallers` attribute applied) and that performs some security-related actions, you must be aware that the constructor is not called. In particular, the following techniques do not work: - -- If you try to restrict partial trust access by making the constructor internal or private, or by adding a `LinkDemand` to the constructor -- neither of these have any effect during deserialization under partial trust. -- If you code the class that assumes the constructor has run, the class may get into an invalid internal state that is exploitable. - ]]> Instances of this class are thread safe except when the instance is used with an implementation of the or . From ca2630de07437fc2c6e829c16b75b786a248374b Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 4 Jun 2026 08:13:54 -0700 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: Bill Wagner --- .../InternalsVisibleToAttribute/Overview/Friend/multiple1.cs | 2 +- .../InternalsVisibleToAttribute/Overview/Friend/multiple2.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs index 25b9cbfd39e..c34be3827d2 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple1.cs @@ -11,7 +11,7 @@ public class StringUtilities internal string ToTitleCase(string value) { string retval = null; - for (int ctr = 0; ctr <= value.Length - 1; ctr++) + for (int ctr = 0; ctr < value.Length; ctr++) if (ctr == 0) retval += Char.ToUpper(value[ctr]); else if (ctr > 0 && Char.IsWhiteSpace(value[ctr - 1])) diff --git a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs index 538a4a5209a..6e53ef42da2 100644 --- a/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs +++ b/snippets/csharp/System.Runtime.CompilerServices/InternalsVisibleToAttribute/Overview/Friend/multiple2.cs @@ -13,7 +13,7 @@ public class StringUtilities1 internal static string ToTitleCase(string value) { string retval = null; - for (int ctr = 0; ctr <= value.Length - 1; ctr++) + for (int ctr = 0; ctr < value.Length; ctr++) if (ctr == 0) retval += Char.ToUpper(value[ctr]); else if (ctr > 0 && Char.IsWhiteSpace(value[ctr - 1]))