Skip to content

Commit b004abc

Browse files
authored
System.Attribute F# snippets (#7522)
* System.Attribute F# snippets * Update customattribute.fs * Update ca2.fs module' -> ilmodule
1 parent c363eb0 commit b004abc

File tree

26 files changed

+1097
-0
lines changed

26 files changed

+1097
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//<Snippet1>
2+
open System
3+
4+
// An enumeration of animals. Start at 1 (0 = uninitialized).
5+
type Animal =
6+
| Dog = 1
7+
| Cat = 2
8+
| Bird = 3
9+
10+
// A custom attribute to allow a target to have a pet.
11+
type AnimalTypeAttribute(pet) =
12+
inherit Attribute()
13+
member val Pet = pet with get, set
14+
15+
// A test class where each method has its own pet.
16+
type AnimalTypeTestClass() =
17+
[<AnimalType(Animal.Dog)>]
18+
member _.DogMethod() = ()
19+
20+
[<AnimalType(Animal.Cat)>]
21+
member _.CatMethod() = ()
22+
23+
[<AnimalType(Animal.Bird)>]
24+
member _.BirdMethod() = ()
25+
26+
let testClass = AnimalTypeTestClass()
27+
let clsType = testClass.GetType()
28+
// Iterate through all the methods of the class.
29+
for mInfo in clsType.GetMethods() do
30+
// Iterate through all the Attributes for each method.
31+
for attr in Attribute.GetCustomAttributes mInfo do
32+
// Check for the AnimalType attribute.
33+
if attr.GetType() = typeof<AnimalTypeAttribute> then
34+
printfn $"Method {mInfo.Name} has a pet {(attr :?> AnimalTypeAttribute).Pet} attribute."
35+
36+
// Output:
37+
// Method DogMethod has a pet Dog attribute.
38+
// Method CatMethod has a pet Cat attribute.
39+
// Method BirdMethod has a pet Bird attribute.
40+
41+
//</Snippet1>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="customattribute.fs" />
8+
</ItemGroup>
9+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module ca1
2+
3+
// <Snippet1>
4+
open System
5+
open System.Reflection
6+
7+
[<assembly: AssemblyTitle "CustAttrs1CS">]
8+
[<assembly: AssemblyDescription "GetCustomAttributes() Demo">]
9+
[<assembly: AssemblyCompany"Microsoft">]
10+
do ()
11+
12+
type Example = class end
13+
14+
// Get the Assembly object to access its metadata.
15+
let assembly = typeof<Example>.Assembly
16+
17+
// Iterate through the attributes for the assembly.
18+
for attr in Attribute.GetCustomAttributes assembly do
19+
match attr with
20+
// Check for the AssemblyTitle attribute.
21+
| :? AssemblyTitleAttribute as attr ->
22+
printfn $"Assembly title is \"{attr.Title}\"."
23+
// Check for the AssemblyDescription attribute.
24+
| :? AssemblyDescriptionAttribute as attr ->
25+
printfn $"Assembly description is \"{attr.Description}\"."
26+
// Check for the AssemblyCompany attribute.
27+
| :? AssemblyCompanyAttribute as attr ->
28+
printfn $"Assembly company is {attr.Company}."
29+
| _ -> ()
30+
31+
// The example displays the following output:
32+
// Assembly title is "CustAttrs1CS".
33+
// Assembly description is "GetCustomAttributes() Demo".
34+
// Assembly company is Microsoft.
35+
// </Snippet1>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module ca2
2+
3+
// <Snippet2>
4+
open System
5+
open System.ComponentModel
6+
7+
// Assign some attributes to the module.
8+
[<``module``: Description "A sample description">]
9+
10+
// Set the module's CLSCompliant attribute to false
11+
// The CLSCompliant attribute is applicable for /target:module.
12+
[<``module``: CLSCompliant false>]
13+
do ()
14+
15+
type DemoClass = class end
16+
17+
// Get the Module type to access its metadata.
18+
let ilmodule = typeof<DemoClass>.Module
19+
20+
// Iterate through all the attributes for the module.
21+
for attr in Attribute.GetCustomAttributes ilmodule do
22+
match attr with
23+
// Check for the Description attribute.
24+
| :? DescriptionAttribute as attr ->
25+
printfn $"Module {ilmodule.Name} has the description \"{attr.Description}\"."
26+
27+
// Check for the CLSCompliant attribute.
28+
| :? CLSCompliantAttribute as attr ->
29+
printfn $"""Module {ilmodule.Name} {if attr.IsCompliant then "is" else "is not"} CLSCompliant."""
30+
| _ -> ()
31+
32+
// Output:
33+
// Module CustAttrs2CS.exe is not CLSCompliant.
34+
// Module CustAttrs2CS.exe has the description "A sample description".
35+
36+
// </Snippet2>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
module ca4
2+
3+
// <Snippet4>
4+
open System
5+
open System.Runtime.InteropServices
6+
7+
// Define an enumeration of Win32 unmanaged types
8+
type UnmanagedType =
9+
| User = 0
10+
| GDI = 1
11+
| Kernel = 2
12+
| Shell = 3
13+
| Networking = 4
14+
| Multimedia = 5
15+
16+
// Define the Unmanaged attribute.
17+
type UnmanagedAttribute(unmanagedType) =
18+
inherit Attribute()
19+
20+
// Define a property to get and set the UnmanagedType value.
21+
member val Win32Type = unmanagedType with get, set
22+
23+
// Create a module for an imported Win32 unmanaged function.
24+
module Win32 =
25+
[<DllImport("user32.dll", CharSet = CharSet.Unicode)>]
26+
extern int MessageBox(IntPtr hWnd, String text, String caption, uint ``type``)
27+
28+
type AClass() =
29+
// Add some attributes to Win32CallMethod.
30+
[<Obsolete "This method is obsolete. Use managed MsgBox instead.">]
31+
[<Unmanaged(UnmanagedType.User)>]
32+
member _.Win32CallMethod () =
33+
Win32.MessageBox(0, "This is an unmanaged call.", "Caution!", 0u)
34+
35+
// Get the AClass type to access its metadata.
36+
let clsType = typeof<AClass>
37+
// Get the type information for Win32CallMethod.
38+
let mInfo = clsType.GetMethod "Win32CallMethod"
39+
if mInfo <> null then
40+
// Iterate through all the attributes of the method.
41+
for attr in Attribute.GetCustomAttributes mInfo do
42+
match attr with
43+
// Check for the Obsolete attribute.
44+
| :? ObsoleteAttribute as attr ->
45+
printfn $"Method {mInfo.Name} is obsolete. The message is:"
46+
printfn $" \"{attr.Message}\""
47+
48+
// Check for the Unmanaged attribute.
49+
| :? UnmanagedAttribute as attr ->
50+
printfn "This method calls unmanaged code."
51+
printfn $"The Unmanaged attribute type is {attr.Win32Type}."
52+
let myCls = AClass()
53+
myCls.Win32CallMethod() |> ignore
54+
| _ -> ()
55+
56+
// This code example produces the following results.
57+
//
58+
// First, the compilation yields the warning, "... This method is
59+
// obsolete. Use managed MsgBox instead."
60+
// Second, execution yields a message box with a title of "Caution!"
61+
// and message text of "This is an unmanaged call."
62+
// Third, the following text is displayed in the console window:
63+
64+
// Method Win32CallMethod is obsolete. The message is:
65+
// "This method is obsolete. Use managed MsgBox instead."
66+
// This method calls unmanaged code.
67+
// The Unmanaged attribute type is User.
68+
69+
// </Snippet4>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module ca5
2+
3+
// <Snippet5>
4+
open System
5+
open System.Reflection
6+
open System.ComponentModel
7+
8+
type AClass() =
9+
member _.ParamArrayAndDesc(
10+
// Add ParamArray and Description attributes.
11+
[<Description "This argument is a ParamArray">]
12+
[<ParamArray>]
13+
args: int[]) = ()
14+
15+
// Get the Class type to access its metadata.
16+
let clsType = typeof<AClass>
17+
18+
// Get the type information for the method.
19+
let mInfo = clsType.GetMethod "ParamArrayAndDesc"
20+
if mInfo <> null then
21+
// Get the parameter information.
22+
let pInfo = mInfo.GetParameters()
23+
if pInfo <> null then
24+
// Iterate through all the attributes for the parameter.
25+
for attr in Attribute.GetCustomAttributes pInfo[0] do
26+
match attr with
27+
// Check for the ParamArray attribute.
28+
| :? ParamArrayAttribute ->
29+
printfn $"Parameter {pInfo[0].Name} for method {mInfo.Name} has the ParamArray attribute."
30+
31+
// Check for the Description attribute.
32+
| :? DescriptionAttribute as attr ->
33+
printfn $"Parameter {pInfo[0].Name} for method {mInfo.Name} has a description attribute."
34+
printfn $"The description is: \"{attr.Description}\""
35+
| _ -> ()
36+
37+
// Output:
38+
// Parameter args for method ParamArrayAndDesc has a description attribute.
39+
// The description is: "This argument is a ParamArray"
40+
// Parameter args for method ParamArrayAndDesc has the ParamArray attribute.
41+
42+
// </Snippet5>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="ca1.fs" />
8+
<Compile Include="ca4.fs" />
9+
<Compile Include="ca2.fs" />
10+
<Compile Include="ca5.fs" />
11+
</ItemGroup>
12+
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="hashcode.fs" />
8+
</ItemGroup>
9+
</Project>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// <Snippet1>
2+
open System
3+
open System.Reflection
4+
open System.Collections.Generic
5+
6+
// A custom attribute to allow two authors per method.
7+
[<AllowNullLiteral>]
8+
type AuthorsAttribute(authorName1, authorName2) =
9+
inherit Attribute()
10+
11+
member val AuthorName1 = authorName1
12+
member val AuthorName2 = authorName2
13+
14+
// Use the hash code of the string objects and xor them together.
15+
override _.GetHashCode() =
16+
authorName1.GetHashCode() ^^^ authorName2.GetHashCode()
17+
18+
// Provide the author names for each method of the class.
19+
type TestClass() =
20+
[<Authors("Immanuel Kant", "Lao Tzu")>]
21+
member _.Method1() = ()
22+
23+
[<Authors("Jean-Paul Sartre", "Friedrich Nietzsche")>]
24+
member _.Method2() = ()
25+
26+
[<Authors("Immanuel Kant", "Lao Tzu")>]
27+
member _.Method3() = ()
28+
29+
[<Authors("Jean-Paul Sartre", "Friedrich Nietzsche")>]
30+
member _.Method4() = ()
31+
32+
[<Authors("Immanuel Kant", "Friedrich Nietzsche")>]
33+
member _.Method5() = ()
34+
35+
// Get the class type to access its metadata.
36+
let clsType = typeof<TestClass>
37+
38+
// Store author information in a array of tuples.
39+
let authorsInfo =
40+
[ // Iterate through all the methods of the class.
41+
for method in clsType.GetMethods() do
42+
// Get the Authors attribute for the method if it exists.
43+
let authAttr =
44+
Attribute.GetCustomAttribute(method, typeof<AuthorsAttribute>) :?> AuthorsAttribute
45+
46+
if authAttr <> null then
47+
// Add the information to the author list.
48+
$"{clsType.Name}.{method.Name}", authAttr ]
49+
50+
// Iterate through the list
51+
printfn "Method authors:\n"
52+
53+
authorsInfo
54+
|> List.groupBy (fun (_, authors) -> authors.AuthorName1, authors.AuthorName2)
55+
|> List.iter (fun ((name1, name2), authors) ->
56+
printfn $"{name1} and {name2}"
57+
for (methodName, _) in authors do
58+
printfn $" {methodName}")
59+
60+
// The example displays the following output:
61+
// Method authors:
62+
//
63+
// Immanuel Kant and Lao Tzu
64+
// TestClass.Method1
65+
// TestClass.Method3
66+
// Jean-Paul Sartre and Friedrich Nietzsche
67+
// TestClass.Method2
68+
// TestClass.Method4
69+
// Immanuel Kant and Friedrich Nietzsche
70+
// TestClass.Method5
71+
// </Snippet1>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// <Snippet1>
2+
open System
3+
4+
// An enumeration of animals. Start at 1 (0 = uninitialized).
5+
type Animal =
6+
| Dog = 1
7+
| Cat = 2
8+
| Bird = 3
9+
10+
// A custom attribute to allow a target to have a pet.
11+
type AnimalTypeAttribute(pet) =
12+
inherit Attribute()
13+
14+
member val Pet = pet
15+
16+
// Override IsDefaultAttribute to return the correct response.
17+
override _.IsDefaultAttribute() =
18+
pet = Animal.Dog
19+
20+
// Provide a default constructor and make Dog the default.
21+
new() = AnimalTypeAttribute Animal.Dog
22+
23+
type TestClass() =
24+
// Use the default constructor.
25+
[<AnimalType>]
26+
member _.Method1() = ()
27+
28+
// Get the class type to access its metadata.
29+
let clsType = typeof<TestClass>
30+
31+
// Get type information for the method.
32+
let mInfo = clsType.GetMethod "Method1"
33+
34+
// Get the AnimalType attribute for the method.
35+
let atAttr =
36+
Attribute.GetCustomAttribute(mInfo, typeof<AnimalTypeAttribute>)
37+
:?> AnimalTypeAttribute
38+
39+
// Check to see if the default attribute is applied.
40+
printf $"The attribute {atAttr.Pet} for method {mInfo.Name} in class {clsType.Name} "
41+
printfn $"""{if atAttr.IsDefaultAttribute() then "is" else "is not"} the default for the AnimalType attribute."""
42+
43+
// Output:
44+
// The attribute Dog for method Method1 in class TestClass is the default for the AnimalType attribute.
45+
46+
// </Snippet1>

0 commit comments

Comments
 (0)