🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
F#-Beispiele
Wesentliche F#-Programmierbeispiele für funktionale Programmierung und .NET-Entwicklung
💻 F# Hello World fsharp
🟢 simple
⭐⭐
Grundlegendes Hello World-Programm und fundamentale funktionale Programmierkonzepte
⏱️ 20 min
🏷️ fsharp, functional programming, dotnet, beginner
Prerequisites:
Basic programming concepts, Understanding of functional programming, .NET basics
// F# Hello World Examples
// 1. Basic Hello World
printfn "Hello, World!"
// 2. Hello World with let binding
let message = "Hello, World!"
printfn "%s" message
// 3. Hello World with function
let sayHello() =
"Hello, World!"
printfn "%s" (sayHello())
// 4. Hello World with function parameters
let greet (name: string) =
sprintf "Hello, %s!" name
printfn "%s" (greet "World")
printfn "%s" (greet "F#")
// 5. Hello World with multiple arities
let greetPerson() = "Hello, Stranger!"
let greetPerson(name: string) = sprintf "Hello, %s!" name
let greetPerson(firstName: string, lastName: string) =
sprintf "Hello, %s %s!" firstName lastName
printfn "%s" (greetPerson())
printfn "%s" (greetPerson "Alice")
printfn "%s" (greetPerson("Jane", "Smith"))
// 6. Hello World with conditionals
let timeGreeting() =
let hour = System.DateTime.Now.Hour
if hour < 12 then
"Good morning, World!"
elif hour < 18 then
"Good afternoon, World!"
else
"Good evening, World!"
printfn "%s" (timeGreeting())
// 7. Hello World multiple times
let repeatGreeting times =
[1..times] |> List.iter (fun i -> printfn "Hello, World! %d" i)
repeatGreeting 5
// 8. Hello World with list
let greetings = ["Hello"; "Bonjour"; "Hola"; "Ciao"; "こんにちは"]
greetings |> List.iter (fun g -> printfn "%s, World!" g)
// 9. Hello World with map
let translateGreetings =
Map [("en", "Hello"); ("es", "Hola"); ("fr", "Bonjour");
("de", "Hallo"); ("ja", "こんにちは")]
translateGreetings
|> Map.iter (fun lang greeting -> printfn "%s, World! (%s)" greeting lang)
// 10. Hello World with recursion
let rec greetCountdown n =
if n > 0 then
printfn "Hello, World! %d" n
greetCountdown (n - 1)
greetCountdown 5
// Basic data types and operations
// Numbers (F# infers types)
let integer = 42 // int
let longInteger = 42L // int64
let floatNumber = 3.14 // float
let doubleNumber = 3.14 // double
let decimalNumber = 3.14m // decimal
// Strings
let text = "Hello, F#!"
let textWithInterpolation = sprintf "The answer is %d" integer
// Characters
let char = 'A'
// Boolean
let boolTrue = true
let boolFalse = false
// Unit (like void)
let unitValue = ()
// Tuples
let tuple1 = (1, "hello")
let tuple2 = (1, "hello", 3.14)
// Lists (immutable linked lists)
let numbers = [1; 2; 3; 4; 5]
let stringList = ["apple"; "banana"; "cherry"]
// Arrays (mutable)
let array = [|1; 2; 3; 4; 5|]
// Maps (immutable dictionaries)
let map = Map [("name", "Alice"); ("age", 30); ("city", "NYC")]
// Sets (immutable)
let set = Set [1; 2; 3; 4; 5]
// Records (immutable)
type Person = { Name: string; Age: int; City: string }
let person = { Name = "Alice"; Age = 30; City = "NYC" }
// Discriminated unions
type Shape =
| Circle of radius: float
| Rectangle of width: float * height: float
| Triangle of base: float * height: float
// Options (for handling nulls)
let someValue: int option = Some 42
let noValue: int option = None
// Data type examples
printfn "\n=== Data Types ==="
printfn "Integer: %d, Type: %A" integer (integer.GetType())
printfn "Float: %f, Type: %A" floatNumber (floatNumber.GetType())
printfn "String: %s, Type: %A" text (text.GetType())
printfn "Boolean: %b, Type: %A" boolTrue (boolTrue.GetType())
printfn "Tuple: %A" tuple1
printfn "List: %A" numbers
printfn "Map: %A" map
printfn "Record: %A" person
// Pattern matching examples
let describeValue x =
match x with
| 0 -> "Zero"
| n when n < 0 -> sprintf "Negative: %d" n
| n when n > 0 -> sprintf "Positive: %d" n
printfn "\n=== Pattern Matching ==="
printfn "Describe 5: %s" (describeValue 5)
printfn "Describe -3: %s" (describeValue -3)
printfn "Describe 0: %s" (describeValue 0)
// Pattern matching with shapes
let area shape =
match shape with
| Circle radius -> System.Math.PI * radius * radius
| Rectangle (width, height) -> width * height
| Triangle (base, height) -> 0.5 * base * height
let circle = Circle 5.0
let rectangle = Rectangle (4.0, 3.0)
let triangle = Triangle (6.0, 4.0)
printfn "\nShape areas:"
printfn "Circle radius 5: %f" (area circle)
printfn "Rectangle 4x3: %f" (area rectangle)
printfn "Triangle 6x4: %f" (area triangle)
// Functions and higher-order functions
// Basic functions
let add x y = x + y
let multiply x y = x * y
// Function composition
let add1 = (+) 1
let multiplyBy2 = (*) 2
let add1ThenMultiply = add1 >> multiplyBy2
let multiplyThenAdd1 = add1 << multiplyBy2
printfn "\n=== Function Composition ==="
printfn "Add 1 then multiply by 2: %d" (add1ThenMultiply 5)
printfn "Multiply by 2 then add 1: %d" (multiplyThenAdd1 5)
// Higher-order functions
let numbersList = [1; 2; 3; 4; 5]
let squares = List.map (fun x -> x * x) numbersList
let evenNumbers = List.filter (fun x -> x % 2 = 0) numbersList
let sum = List.reduce (+) numbersList
printfn "\n=== Higher-Order Functions ==="
printfn "Original: %A" numbersList
printfn "Squares: %A" squares
printfn "Even: %A" evenNumbers
printfn "Sum: %d" sum
// Pipeline operator
let result =
numbersList
|> List.map (fun x -> x * x)
|> List.filter (fun x -> x > 5)
|> List.sum
printfn "Pipeline result: %d" result
// List comprehensions
let moreSquares = [for x in 1..10 -> x * x]
let evenSquares = [for x in 1..10 do
let square = x * x
if square % 2 = 0 then yield square]
printfn "\n=== List Comprehensions ==="
printfn "More squares: %A" moreSquares
printfn "Even squares: %A" evenSquares
// Option handling
let safeDivide x y =
if y = 0 then None
else Some (x / y)
let divideAndPrint x y =
match safeDivide x y with
| Some result -> printfn "%d / %d = %d" x y result
| None -> printfn "Cannot divide %d by zero" x
printfn "\n=== Option Handling ==="
divideAndPrint 10 2
divideAndPrint 10 0
// Working with records
type Employee = {
Name: string
Department: string
Salary: float
Skills: string list
}
let employees = [
{ Name = "Alice"; Department = "Engineering"; Salary = 80000.0; Skills = ["F#"; "C#"; "SQL"] }
{ Name = "Bob"; Department = "Marketing"; Salary = 65000.0; Skills = ["Marketing"; "Analytics"] }
{ Name = "Charlie"; Department = "Engineering"; Salary = 90000.0; Skills = ["Python"; "Java"; "F#"] }
]
let findEmployeesByDepartment dept =
employees
|> List.filter (fun emp -> emp.Department = dept)
let getAllSkills() =
employees
|> List.collect (fun emp -> emp.Skills)
|> Set.ofList
|> Set.toList
printfn "\n=== Record Operations ==="
printfn "Engineering employees: %A" (findEmployeesByDepartment "Engineering")
printfn "All skills: %A" (getAllSkills())
// Discriminated unions with pattern matching
type TrafficLight =
| Red
| Yellow
| Green
let trafficAction light =
match light with
| Red -> "Stop"
| Yellow -> "Prepare to stop"
| Green -> "Go"
printfn "\n=== Discriminated Unions ==="
printfn "Red light action: %s" (trafficAction Red)
printfn "Green light action: %s" (trafficAction Green)
// Active patterns
let (|Even|Odd|) x =
if x % 2 = 0 then Even else Odd
let describeNumber2 x =
match x with
| Even -> sprintf "%d is even" x
| Odd -> sprintf "%d is odd" x
printfn "\n=== Active Patterns ==="
printfn "Describe 4: %s" (describeNumber2 4)
printfn "Describe 7: %s" (describeNumber2 7)
// Exception handling
let riskyOperation x =
if x < 0 then
failwith "Negative numbers not allowed"
else
sqrt (float x)
let safeOperation x =
try
let result = riskyOperation x
Some result
with
| ex ->
printfn "Error: %s" ex.Message
None
printfn "\n=== Exception Handling ==="
printfn "Safe operation with 9: %A" (safeOperation 9)
printfn "Safe operation with -4: %A" (safeOperation -4)
// Computation expressions (async)
let downloadData url = async {
printfn "Downloading from %s" url
do! Async.Sleep 1000 // Simulate network delay
return sprintf "Data from %s" url
}
let processData data = async {
printfn "Processing: %s" data
do! Async.Sleep 500
return sprintf "Processed: %s" data
}
let downloadAndProcess url = async {
let! data = downloadData url
let! processed = processData data
return processed
}
// Async execution example
printfn "\n=== Async Operations ==="
let asyncResult = downloadAndProcess "http://example.com/data"
printfn "Async result: %s" (Async.RunSynchronously asyncResult)
// Classes and objects
type Calculator() =
member this.Add(x, y) = x + y
member this.Subtract(x, y) = x - y
member this.Multiply(x, y) = x * y
let calculator = Calculator()
printfn "\n=== Class Example ==="
printfn "Calculator Add: %d" (calculator.Add(5, 3))
printfn "Calculator Multiply: %d" (calculator.Multiply(4, 7))
// Interface implementation
type IShape =
abstract member Area : float
type Square(side: float) =
interface IShape with
member this.Area = side * side
let square = Square(5.0)
printfn "Square area: %f" (square :> IShape).Area
// Mutable vs Immutable
// Immutable (preferred)
let mutableValue = 10
printfn "\n=== Mutability ==="
printfn "Original value: %d" mutableValue
// This requires the mutable keyword
let mutable mutableRef = 20
mutableRef <- 30
printfn "Changed value: %d" mutableRef
// Unit testing functions
let add a b = a + b
let multiply a b = a * b
let testAddition() =
let result = add 2 3
if result = 5 then
printfn "✓ Addition test passed"
else
printfn "✗ Addition test failed: expected 5, got %d" result
let testMultiplication() =
let result = multiply 4 5
if result = 20 then
printfn "✓ Multiplication test passed"
else
printfn "✗ Multiplication test failed: expected 20, got %d" result
printfn "\n=== Simple Tests ==="
testAddition()
testMultiplication()
// String operations
let stringOperations() =
let text = "Hello, F# Programming!"
printfn "Original: %s" text
printfn "Upper case: %s" (text.ToUpper())
printfn "Lower case: %s" (text.ToLower())
printfn "Length: %d" (text.Length)
printfn "Contains 'F#': %b" (text.Contains "F#")
printfn "Split words: %A" (text.Split([|' '; ','; '!'|], System.StringSplitOptions.RemoveEmptyEntries))
printfn "Replace 'F#' with 'Fsharp': %s" (text.Replace("F#", "Fsharp"))
stringOperations()
// Working with DateTime
let dateTimeOperations() =
let now = System.DateTime.Now
let tomorrow = now.AddDays 1.0
let formatted = now.ToString("yyyy-MM-dd HH:mm:ss")
printfn "\n=== DateTime Operations ==="
printfn "Current time: %s" formatted
printfn "Tomorrow: %s" (tomorrow.ToString("yyyy-MM-dd"))
printfn "Day of week: %s" (now.DayOfWeek.ToString())
dateTimeOperations()
printfn "\n=== All F# Hello World Examples Complete! ==="
💻 F# Funktionale Programmiermuster fsharp
🟡 intermediate
⭐⭐⭐⭐
Fortgeschrittene funktionale Programmiermuster, Berechnungsausdrücke und Typanbieter
⏱️ 35 min
🏷️ fsharp, functional programming, advanced, patterns, .net
Prerequisites:
F# basics, Advanced functional programming concepts, .NET framework
// F# Functional Programming Patterns
// 1. Advanced Pattern Matching
// Pattern matching with nested data structures
type Tree<'T> =
| Leaf of 'T
| Node of Tree<'T> * Tree<'T>
let rec treeSum tree =
match tree with
| Leaf value -> value
| Node (left, right) -> (treeSum left) + (treeSum right)
let myTree = Node (Node (Leaf 3, Leaf 7), Leaf 5)
printfn "Tree sum: %d" (treeSum myTree)
// Pattern matching with when guards
let classifyNumber x =
match x with
| x when x < 0 -> "Negative"
| x when x = 0 -> "Zero"
| x when x % 2 = 0 -> "Even positive"
| _ -> "Odd positive"
printfn "Classify -5: %s" (classifyNumber -5)
printfn "Classify 4: %s" (classifyNumber 4)
printfn "Classify 7: %s" (classifyNumber 7)
// List patterns
let processList list =
match list with
| [] -> "Empty list"
| [x] -> sprintf "Single element: %d" x
| [x; y] -> sprintf "Two elements: %d, %d" x y
| head :: tail -> sprintf "Head: %d, Tail: %A" head tail
printfn "Process []: %s" (processList [])
printfn "Process [42]: %s" (processList [42])
printfn "Process [1; 2; 3]: %s" (processList [1; 2; 3])
// 2. Active Patterns
// Single-case active pattern
let (|Even|Odd|) x = if x % 2 = 0 then Even else Odd
let describeNumberWithActivePattern x =
match x with
| Even when x > 0 -> sprintf "%d is positive even" x
| Odd when x > 0 -> sprintf "%d is positive odd" x
| Even -> sprintf "%d is zero or negative even" x
| Odd -> sprintf "%d is negative odd" x
printfn "Active pattern describe 4: %s" (describeNumberWithActivePattern 4)
// Parameterized active pattern
let (|DivisibleBy|_|) divisor x =
if x % divisor = 0 then Some (x / divisor) else None
let checkDivisibility x =
match x with
| DivisibleBy 3 quotient -> sprintf "%s is divisible by 3, quotient is %d" x quotient
| DivisibleBy 5 quotient -> sprintf "%s is divisible by 5, quotient is %d" x quotient
| _ -> sprintf "%s is not divisible by 3 or 5" x
printfn "Check 15: %s" (checkDivisibility 15)
printfn "Check 14: %s" (checkDivisibility 14)
// Partial active pattern
let (|FirstElement|_|) list =
match list with
| head :: _ -> Some head
| [] -> None
let getFirstElementDescription list =
match list with
| FirstElement element -> sprintf "First element is %d" element
| _ -> "List is empty"
printfn "First element [1;2;3]: %s" (getFirstElementDescription [1; 2; 3])
printfn "First element []: %s" (getFirstElementDescription [])
// 3. Higher-Order Functions and Function Composition
// Currying
let curry (f: 'a * 'b -> 'c) : 'a -> 'b -> 'c =
fun x y -> f (x, y)
let uncurry (f: 'a -> 'b -> 'c) : 'a * 'b -> 'c =
fun (x, y) -> f x y
// Usage
let addTuple (x, y) = x + y
let addCurried = curry addTuple
let addUncurried = uncurry add
printfn "Curried: %d" (addCurried 5 3)
printfn "Uncurried: %d" (addUncurried (5, 3))
// Function composition with types
let compose (g: 'b -> 'c) (f: 'a -> 'b) : 'a -> 'c =
fun x -> g (f x)
// Forward composition operator (|)
let (|>) x f = f x
let (>>) g f = compose g f
// Pipeline with complex operations
let processNumber x =
x
|> float
|> sqrt
|> (*) 2.0
|> int
printfn "Process number 16: %d" (processNumber 16)
// 4. Immutability and Persistent Data Structures
// Persistent stack implementation
type PersistentStack<'T>(private items: 'T list) =
member this.IsEmpty = List.isEmpty items
member this.Push item = PersistentStack (item :: items)
member this.Pop() =
match items with
| [] -> None, this
| head :: tail -> Some head, PersistentStack tail
member this.Peek() = List.head items
// Usage
let stack = PersistentStack [3; 2; 1]
let Some(head, newStack) = stack.Pop()
printfn "Stack peek before: %d" stack.Peek
printfn "Stack pop: %d" head.Value
printfn "Stack peek after: %d" newStack.Peek
let finalStack = newStack.Push(4)
printfn "Final stack peek: %d" finalStack.Peek
// 5. Option and Result Types for Error Handling
// Result type (not built-in, so we create it)
type Result<'T, 'E> =
| Success of 'T
| Error of 'E
// Safe operations with Result type
let safeDivideResult x y =
if y = 0 then
Error "Division by zero"
else
Success (x / y)
// Result chaining
let bind (f: 'T -> Result<'U, 'E>) (result: Result<'T, 'E>) : Result<'U, 'E> =
match result with
| Success value -> f value
| Error error -> Error error
let map (f: 'T -> 'U) (result: Result<'T, 'E>) : Result<'U, 'E> =
match result with
| Success value -> Success (f value)
| Error error -> Error error
// Pipeline operator for Result type
let (|>>) result f = bind f
// Usage
let calculation =
Success 20
|>> safeDivideResult 2 // Success 10
|>> safeDivideResult 5 // Success 2
|>> safeDivideResult 0 // Error "Division by zero"
match calculation with
| Success result -> printfn "Calculation succeeded: %d" result
| Error error -> printfn "Calculation failed: %s" error
// 6. Computation Expressions (Workflow)
// Maybe computation expression
type MaybeBuilder() =
member __.Return(x) = Some x
member __.Bind(m, f) =
match m with
| Some value -> f value
| None -> None
member __.Zero() = None
member __.Delay(f) = f()
member __.Combine(a, b) =
match a with
| Some _ -> b
| None -> None
let maybe = MaybeBuilder()
// Using maybe computation expression
let safeDivideMaybe x y =
if y = 0 then None
else Some (x / y)
let complexCalculation x =
maybe {
let! a = safeDivideMaybe x 2
let! b = safeDivideMaybe a 3
let! c = safeDivideMaybe b 4
return c
}
printfn "Maybe calculation 24: %A" (complexCalculation 24)
printfn "Maybe calculation 0: %A" (complexCalculation 0)
// 7. Async Computation Expressions
// Async workflow operations
let downloadDataAsync url = async {
printfn "Downloading from %s" url
do! Async.Sleep 1000 // Simulate network delay
return sprintf "Data from %s" url
}
let processDataAsync data = async {
printfn "Processing: %s" data
do! Async.Sleep 500 // Simulate processing delay
return sprintf "Processed: %s" data
}
let validateDataAsync processedData = async {
printfn "Validating: %s" processedData
do! Async.Sleep 200 // Simulate validation delay
return processedData.Length > 10
}
let completeWorkflow url = async {
try
let! data = downloadDataAsync url
let! processed = processDataAsync data
let! isValid = validateDataAsync processed
if isValid then
return Success processed
else
return Error "Validation failed: data too short"
with
| ex -> return Error (sprintf "Workflow failed: %s" ex.Message)
}
// Async workflow execution
let workflowResult = completeWorkflow "http://example.com/data" |> Async.RunSynchronously
printfn "Workflow result: %A" workflowResult
// 8. List Processing with Pipelines
// Advanced list operations
let numbers = [1..100]
let processingPipeline =
numbers
|> List.filter (fun x -> x % 2 = 0) // Filter evens
|> List.map (fun x -> x * x) // Square them
|> List.filter (fun x -> x > 100) // Filter > 100
|> List.take 10 // Take first 10
|> List.sum // Sum them up
printfn "Processing pipeline result: %d" processingPipeline
// Fallback operator
let safeHead defaultValue list =
list
|> List.tryHead
|> Option.defaultValue defaultValue
printfn "Safe head with non-empty: %d" (safeHead 0 [1; 2; 3])
printfn "Safe head with empty: %d" (safeHead 0 [])
// 9. Discriminated Unions for Domain Modeling
type PaymentMethod =
| CreditCard of number: string * cvv: string * expiry: string
| PayPal of email: string
| BankTransfer of accountNumber: string * bankName: string
type PaymentStatus =
| Pending
| Completed
| Failed of errorMessage: string
type PaymentResult = {
Amount: decimal
Method: PaymentMethod
Status: PaymentStatus
Timestamp: System.DateTime
}
let processPayment amount paymentMethod =
let status =
match paymentMethod with
| CreditCard (number, cvv, expiry) ->
if String.length number = 16 && String.length cvv = 3 then
Completed
else
Failed "Invalid card details"
| PayPal email ->
if email.Contains "@" then
Completed
else
Failed "Invalid email address"
| BankTransfer (account, bank) ->
if String.length account >= 8 then
Completed
else
Failed "Invalid account number"
{
Amount = amount
Method = paymentMethod
Status = status
Timestamp = System.DateTime.Now
}
// Usage
let creditCardPayment = CreditCard ("1234567890123456", "123", "12/25")
let paymentResult = processPayment 50.0m creditCardPayment
printfn "Payment result: %A" paymentResult
// 10. Type Providers (mocked since they require external data)
// JSON Type Provider simulation
type JsonData = {
Name: string
Age: int
City: string
}
let jsonExample = """
{
"name": "Alice",
"age": 30,
"city": "New York"
}
"""
// In real F#, you would use FSharp.Data to create types from JSON
// let jsonProvider = JsonProvider<"""{ "name": string, "age": int }""">
// 11. Memoization and Caching
// Simple memoization
let memoize (f: 'a -> 'b) =
let cache = System.Collections.Generic.Dictionary<'a, 'b>()
fun x ->
match cache.TryGetValue(x) with
| true, cachedValue -> cachedValue
| false, _ ->
let result = f x
cache.[x] <- result
result
// Memoized Fibonacci
let rec fib n = if n < 2 then n else fib(n-1) + fib(n-2)
let memoizedFib = memoize fib
printfn "Memoized fib 30: %d" (memoizedFib 30)
printfn "Memoized fib 30 again: %d" (memoizedFib 30) // Cached
// 12. Lazy Evaluation
let expensiveOperation x =
printfn "Computing expensive operation for %d" x
System.Threading.Thread.Sleep(1000)
x * x
let lazyValue = lazy (expensiveOperation 42)
printfn "Lazy value created (not computed yet)"
printfn "Lazy value: %d" lazyValue.Force()
printfn "Lazy value (cached): %d" lazyValue.Force()
// 13. Agent-based Programming (MailboxProcessor)
type Message =
| Increment
| Decrement
| GetValue of replyChannel: AsyncReplyChannel<int>
| Stop
let counterAgent = MailboxProcessor.Start(fun inbox ->
let rec loop count =
async {
let! message = inbox.Receive()
match message with
| Increment -> return! loop (count + 1)
| Decrement -> return! loop (count - 1)
| GetValue replyChannel ->
replyChannel.Reply count
return! loop count
| Stop -> ()
}
loop 0)
let agentExample = async {
counterAgent.Post Increment
counterAgent.Post Increment
counterAgent.Post Increment
counterAgent.Post Decrement
let! value = counterAgent.PostAndReply GetValue
printfn "Counter value: %d" value
counterAgent.Post Stop
}
agentExample |> Async.RunSynchronously
// 14. Working with Units of Measure
[<Measure>] type m
[<Measure>] type s
[<Measure>] type kg
let distance = 5.0<m>
let time = 2.0<s>
// This would not compile: let invalid = distance + time
let speed = distance / time // Results in float<m/s>
printfn "Speed: %f m/s" speed
// 15. Quotations and Code Generation
open Microsoft.FSharp.Quotations
let simpleQuotation = <@ 1 + 2 @>
printfn "Quotation: %A" simpleQuotation
let functionQuotation = <@ fun x -> x * 2 @>
printfn "Function quotation: %A" functionQuotation
// Expression tree evaluation (simplified)
let eval (expr: Expr<int>) : int =
match expr with
| Patterns.Value(v, _) -> v
| Patterns.Call(None, op, [Patterns.Value(a, _); Patterns.Value(b, _)]) ->
match op with
| Patterns.ValueWithReflection("op_Addition", _) -> a + b
| Patterns.ValueWithReflection("op_Multiply", _) -> a * b
| _ -> failwith "Unsupported operation"
| _ -> failwith "Unsupported expression"
let additionQuotation = <@ 3 + 4 @>
printfn "Evaluated quotation: %d" (eval additionQuotation)
// 16. Reflection and Type Introspection
let examineType<'T>() =
let t = typeof<'T>
printfn "Type: %s" t.Name
printfn "Namespace: %s" t.Namespace
printfn "Is abstract: %b" t.IsAbstract
printfn "Properties: %A" (t.GetProperties() |> Array.map (fun p -> p.Name))
examineType<System.String>()
printfn "\n=== All Functional Programming Patterns Complete! ==="
💻 F# .NET-Interoperabilität fsharp
🟡 intermediate
⭐⭐⭐⭐
Nahtlose Integration mit C#, VB.NET und dem .NET-Ökosystem einschließlich Enterprise-Patterns
⏱️ 40 min
🏷️ fsharp, dotnet, interoperability, enterprise, backend
Prerequisites:
F# basics, C# knowledge, .NET framework understanding, Enterprise patterns
// F# .NET Interoperability Examples
// 1. Basic .NET Interoperability
// Using .NET classes
open System
open System.Collections.Generic
open System.IO
// Working with DateTime
let getCurrentDateTime() =
let now = DateTime.Now
printfn "Current date and time: %s" (now.ToString("yyyy-MM-dd HH:mm:ss"))
printfn "Day of week: %s" (now.DayOfWeek.ToString())
printfn "Year: %d" now.Year
getCurrentDateTime()
// Working with .NET collections
let workWithCollections() =
// List<T>
let mutable stringList = List<string>()
stringList.Add("Hello")
stringList.Add("F#")
stringList.Add("DotNet")
printfn "List<T> contents:"
for item in stringList do
printfn " %s" item
// Dictionary<TKey, TValue>
let dict = Dictionary<string, int>()
dict.["one"] <- 1
dict.["two"] <- 2
dict.["three"] <- 3
printfn "\nDictionary contents:"
for kvp in dict do
printfn " %s = %d" kvp.Key kvp.Value
workWithCollections()
// 2. Interacting with C# classes and interfaces
// Define C#-style interface
type ILogger =
abstract member Log: string -> unit
abstract member LogError: string * exn -> unit
// C#-style class implementing interface
type ConsoleLogger() =
interface ILogger with
member _.Log(message) = printfn "INFO: %s" message
member _.LogError(message, ex) =
printfn "ERROR: %s - %s" message ex.Message
// Usage
let logger = ConsoleLogger()
logger.Log("Application started")
logger.LogError("Something went wrong", (ArgumentNullException("param")))
// 3. Extension Methods (as module functions)
module StringExtensions =
let ToPascalCase (str: string) =
if String.IsNullOrEmpty(str) then str
else
let words = str.Split([|' '; '-'; '_'|], StringSplitOptions.RemoveEmptyEntries)
words
|> Array.map (fun w ->
if String.IsNullOrEmpty(w) then w
else string w.[0].ToUpper() + w.Substring(1).ToLower())
|> String.concat
// Usage
let testString = "hello_world_from_f#"
let pascalCase = StringExtensions.ToPascalCase testString
printfn "Pascal case of '%s': %s" testString pascalCase
// 4. C# Property Patterns in F#
type Person(name: string, age: int) =
member _.Name = name
member _.Age = age
member _.IsAdult = age >= 18
member _.Description = sprintf "%s is %d years old" name age
// Create instance
let person = Person("Alice", 30)
printfn "Person: %s" person.Description
printfn "Is adult: %b" person.IsAdult
// 5. Implementing IDisposable pattern
type DatabaseConnection(connectionString: string) =
let mutable isConnected = false
member _.Connect() =
if not isConnected then
printfn "Connecting to database: %s" connectionString
isConnected <- true
else
printfn "Already connected to database"
member _.Disconnect() =
if isConnected then
printfn "Disconnecting from database"
isConnected <- false
else
printfn "Already disconnected"
interface IDisposable with
member _.Dispose() = _.Disconnect()
// Usage with using block
let useDatabase() =
use connection = DatabaseConnection("Server=localhost;Database=Test;")
connection.Connect()
printfn "Working with database connection..."
// Connection is automatically disposed when using block ends
useDatabase()
// 6. Working with .NET Events
type EventBus() =
let event = new Event<EventHandler<EventArgs>>()
[<CLIEvent>]
member _.OnMessage = event.Publish
member _.TriggerMessage(message: string) =
let args = EventArgs()
printfn "Triggering event with message: %s" message
event.Trigger(this, args)
let eventBus = EventBus()
// Subscribe to event (C#-style)
let eventHandler (sender: obj) (e: EventArgs) =
printfn "Event received from %A at %s" sender (DateTime.Now.ToString())
// Add event listener
eventBus.OnMessage.AddHandler(EventHandler<EventArgs>(eventHandler))
// Trigger event
eventBus.TriggerMessage("Hello from F#!")
// 7. LINQ Integration
// Using LINQ with F#
open System.Linq
let useLinq() =
let numbers = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
// Convert to .NET IEnumerable and use LINQ
let enumerable = numbers :> IEnumerable<int>
// LINQ operations
let evenNumbers = enumerable.Where(fun x -> x % 2 = 0)
let sortedNumbers = numbers.OrderByDescending(fun x -> x)
let groupedNumbers = numbers.GroupBy(fun x -> x % 3)
printfn "Even numbers (LINQ): %A" (Seq.toList evenNumbers)
printfn "Sorted descending (LINQ): %A" (Seq.toList sortedNumbers)
printfn "Grouped by mod 3:"
for group in groupedNumbers do
printfn " Mod %d: %A" group.Key (Seq.toList group)
useLinq()
// 8. Async/Await Integration with C# patterns
type HttpClient() =
member _.GetAsync(url: string) = async {
printfn "Making GET request to %s" url
do! Async.Sleep 1000 // Simulate network delay
return sprintf "Response from %s" url
}
member _.PostAsync(url: string, data: string) = async {
printfn "Making POST request to %s with data: %s" url data
do! Async.Sleep 1500 // Simulate network delay
return sprintf "Posted data to %s" url
}
let httpClient = HttpClient()
// Async workflow similar to C# async/await
let makeApiCalls() = async {
try
let! response1 = httpClient.GetAsync("https://api.example.com/users")
printfn "GET response: %s" response1
let! response2 = httpClient.PostAsync("https://api.example.com/data", "{'key': 'value'}")
printfn "POST response: %s" response2
return ["GET result: " + response1; "POST result: " + response2]
with
| ex ->
printfn "API call failed: %s" ex.Message
return ["Error: " + ex.Message]
}
// Execute async workflow
let apiResults = makeApiCalls() |> Async.RunSynchronously
printfn "API results: %A" apiResults
// 9. Interoperability with C# Null Handling
let handleNullable() =
// Working with nullable types
let nullableInt: Nullable<int> = Nullable(42)
let nullableIntNull = Nullable()
printfn "Nullable int: %d" nullableInt.Value
printfn "Nullable int.HasValue: %b" nullableInt.HasValue
printfn "Nullable int null.HasValue: %b" nullableIntNull.HasValue
// Convert to F# Option
let nullableToOption (nullable: Nullable<'T>) =
if nullable.HasValue then Some nullable.Value else None
let optionFromNull = nullableToOption nullableIntNull
printfn "Option from null nullable: %A" optionFromNull
handleNullable()
// 10. C# Attributes in F#
// Using .NET attributes
[<Serializable>]
type UserData =
{
[<System.ComponentModel.DisplayName("User ID")>]
Id: int
[<System.ComponentModel.Description("The user's name")>]
Name: string
[<System.ComponentModel.DefaultValue("")>]
Email: string
}
// Reflection on attributes
let inspectAttributes() =
let userType = typeof<UserData>
let properties = userType.GetProperties()
printfn "UserData properties with attributes:"
for prop in properties do
let displayName =
prop.GetCustomAttributes(typeof<System.ComponentModel.DisplayNameAttribute>, false)
|> Seq.tryHead
|> Option.map (fun attr -> attr.DisplayName)
|> Option.defaultValue prop.Name
let description =
prop.GetCustomAttributes(typeof<System.ComponentModel.DescriptionAttribute>, false)
|> Seq.tryHead
|> Option.map (fun attr -> attr.Description)
|> Option.defaultValue ""
printfn " %s (%s): %s" displayName prop.PropertyType.Name description
inspectAttributes()
// 11. Task Parallel Library Integration
let useParallelLibrary() =
let numbers = [1..20]
// Parallel.For (imperative)
Array.Parallel.For(numbers |> Array.ofList, fun x ->
let result = x * x
printfn "Processing %d -> %d" x result
) |> ignore
// Parallel.ForEach
let words = ["hello"; "world"; "fsharp"; "parallel"]
Parallel.ForEach(words, fun word ->
printfn "Processing word: %s (length: %d)" word word.Length
) |> ignore
// PLINQ
let parallelResult =
numbers
|> AsParallel()
|> Where(fun x -> x % 2 = 0)
|> Select(fun x -> x * x)
|> ToArray()
printfn "PLINQ even squares: %A" parallelResult
useParallelLibrary()
// 12. Configuration and AppSettings
type AppConfiguration() =
member val ConnectionString = "Server=localhost;Database=MyApp;" with get, set
member val LogLevel = "Info" with get, set
member val MaxRetries = 3 with get, set
member val ApiKey = "default-key" with get, set
member _.LoadFromFile(filePath: string) =
if File.Exists(filePath) then
let lines = File.ReadAllLines(filePath)
for line in lines do
let parts = line.Split('=')
if parts.Length = 2 then
match parts.[0].Trim() with
| "ConnectionString" -> _.ConnectionString <- parts.[1].Trim()
| "LogLevel" -> _.LogLevel <- parts.[1].Trim()
| "MaxRetries" -> _.MaxRetries <- int parts.[1].Trim()
| "ApiKey" -> _.ApiKey <- parts.[1].Trim()
| _ -> ()
else
printfn "Config file not found: %s" filePath
// Usage
let config = AppConfiguration()
printfn "Default config: ConnectionString=%s, LogLevel=%s" config.ConnectionString config.LogLevel
// 13. Dependency Injection Patterns
type ILogger2 =
abstract member LogInfo: string -> unit
abstract member LogWarning: string -> unit
abstract member LogError: string -> unit
type FileLogger(filePath: string) =
interface ILogger2 with
member _.LogInfo(message) =
File.AppendAllText(filePath, sprintf "[INFO] %s: %s%s"
(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)
member _.LogWarning(message) =
File.AppendAllText(filePath, sprintf "[WARN] %s: %s%s"
(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)
member _.LogError(message) =
File.AppendAllText(filePath, sprintf "[ERROR] %s: %s%s"
(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)
type UserService(logger: ILogger2) =
member _.CreateUser(name: string, email: string) =
logger.LogInfo(sprintf "Creating user with name: %s, email: %s" name email)
// User creation logic here
{ Name = name; Email = email; CreatedAt = DateTime.Now }
type UserRepository =
member _.Save(user) =
// Database save logic here
printfn "Saving user: %A" user
type Application(logger: ILogger2) =
let userService = UserService(logger)
let userRepository = UserRepository()
member _.RegisterUser(name: string, email: string) =
logger.LogInfo("Starting user registration")
let user = userService.CreateUser(name, email)
userRepository.Save(user)
logger.LogInfo(sprintf "User registered successfully: %s" name)
// Dependency injection usage
let fileLogger = FileLogger("app.log")
let application = Application(fileLogger)
application.RegisterUser "John Doe" "[email protected]"
// 14. Interop with C# async patterns (Task-based)
type CSharpStyleService() =
// Method returning Task<T> like in C#
member _.GetDataAsync() : System.Threading.Tasks.Task<string> =
System.Threading.Tasks.Task.Run(fun () ->
System.Threading.Thread.Sleep(1000)
"Data from C#-style service"
)
member _.ProcessDataAsync(data: string) : System.Threading.Tasks.Task<bool> =
System.Threading.Tasks.Task.Run(fun () ->
System.Threading.Thread.Sleep(500)
not (String.IsNullOrEmpty(data))
)
// Convert C# Task to F# Async
let taskToAsync (task: System.Threading.Tasks.Task<'T>) : Async<'T> =
Async.FromContinuations((fun (success, error, canceled) ->
task.ContinueWith(fun (t: System.Threading.Tasks.Task<'T>) ->
if t.IsFaulted then
error (t.Exception)
elif t.IsCanceled then
canceled ()
else
success t.Result)))
let callCSharpService() = async {
let service = CSharpStyleService()
// Convert Task to Async
let! data = service.GetDataAsync() |> taskToAsync
let! isValid = service.ProcessDataAsync(data) |> taskToAsync
if isValid then
return sprintf "Valid data from C# service: %s" data
else
return "Invalid data from C# service"
}
let csharpResult = callCSharpService() |> Async.RunSynchronously
printfn "C# service result: %s" csharpResult
// 15. JSON Serialization with Newtonsoft.Json (like C#)
type Product = {
Id: int
Name: string
Price: decimal
InStock: bool
}
let serializeToJson() =
open Newtonsoft.Json
let product = { Id = 1; Name = "Laptop"; Price = 999.99m; InStock = true }
// Serialize to JSON
let json = JsonConvert.SerializeObject(product, Formatting.Indented)
printfn "Serialized JSON:\n%s" json
// Deserialize from JSON
let deserializedProduct = JsonConvert.DeserializeObject<Product>(json)
printfn "Deserialized product: %A" deserializedProduct
serializeToJson()
// 16. Database Operations with Entity Framework patterns
// Mock Entity Framework-like operations
type DbContext(connectionString: string) =
member _.SaveChanges() =
printfn "Saving changes to database with connection: %s" connectionString
1 // Return number of affected rows
type UserRepository2(db: DbContext) =
member _.Add(user: UserData) =
printfn "Adding user to database: %A" user
user
member _.Update(user: UserData) =
printfn "Updating user in database: %A" user
user
member _.Delete(id: int) =
printfn "Deleting user with ID: %d" id
member _.FindById(id: int) =
// Simulate database lookup
if id > 0 then
Some { Id = id; Name = sprintf "User %d" id; Email = sprintf "user%[email protected]" id }
else
None
// Repository pattern usage
let dbContext = DbContext("Server=localhost;Database=Test;")
let userRepository2 = UserRepository2(dbContext)
let performDatabaseOperations() =
// Create
let newUser = userRepository2.Add({ Id = 0; Name = "New User"; Email = "[email protected]" })
// Update
let updatedUser = { newUser with Name = "Updated User" }
userRepository2.Update(updatedUser) |> ignore
// Read
match userRepository2.FindById(1) with
| Some user -> printfn "Found user: %A" user
| None -> printfn "User not found"
// Save changes
let rowsAffected = dbContext.SaveChanges()
printfn "Rows affected: %d" rowsAffected
performDatabaseOperations()
printfn "\n=== All F# .NET Interoperability Examples Complete! ==="