C# Geliştirici İpuçları
C# ile daha verimli kod yazmanızı sağlayacak ipuçları ve yöntemler.

C# Geliştirici İpuçları
C# ile çalışan geliştiriciler için performans, okunabilirlik ve maintainability açısından önemli ipuçları ve best practice'ler. Bu yazıda deneyimli geliştiricilerin kullandığı teknikleri paylaşacağım.
Kurumsal Çözümler: Özel yazılım projeleriniz ve backend ihtiyaçlarınız için Web ve Kurumsal Yazılım konusundaki uzmanlığımızdan faydalanın.
1. Modern C# Özellikleri
Null-conditional Operators
// Eski yöntem
if (user != null && user.Profile != null && user.Profile.Address != null)
{
var city = user.Profile.Address.City;
}
// Modern yöntem
var city = user?.Profile?.Address?.City;
Pattern Matching
// C# 8.0+ Switch Expressions
public string GetDiscountType(decimal amount) => amount switch
{
< 100 => "No discount",
>= 100 and < 500 => "Bronze",
>= 500 and < 1000 => "Silver",
>= 1000 => "Gold",
_ => throw new ArgumentException("Invalid amount")
};
// C# 11+ List Patterns
public string AnalyzeNumbers(int[] numbers) => numbers switch
{
[] => "Empty array",
[var x] => $"Single element: {x}",
[var x, var y] => $"Two elements: {x}, {y}",
[var first, .., var last] => $"Multiple elements: {first}...{last}",
_ => "Unknown pattern"
};
Record Types
// Immutable record
public record Person(string Name, int Age);
// Mutable record
public record PersonMutable
{
public string Name { get; set; }
public int Age { get; set; }
}
// Usage
var person = new Person("John", 30);
var olderPerson = person with { Age = 31 }; // Creates new instance
2. Performans İpuçları
StringBuilder vs String Concatenation
// Yavaş - her concatenation'da yeni string oluşur
string result = "";
for (int i = 0; i < 1000; i++)
{
result += $"Item {i}";
}
// Hızlı - StringBuilder kullanımı
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append($"Item {i}");
}
string result = sb.ToString();
Span ve Memory
// Heap allocation olmadan string slice
ReadOnlySpan<char> span = "Hello, World!".AsSpan();
ReadOnlySpan<char> hello = span.Slice(0, 5); // "Hello"
// Array işlemleri için Span kullanımı
int[] numbers = { 1, 2, 3, 4, 5 };
Span<int> span = numbers.AsSpan();
var slice = span.Slice(1, 3); // [2, 3, 4]
Async/Await Best Practices
// ConfigureAwait(false) kullanımı
public async Task<string> GetDataAsync()
{
var result = await httpClient.GetStringAsync(url)
.ConfigureAwait(false);
return result;
}
// ValueTask kullanımı - sıkça çağrılan metodlar için
public ValueTask<int> GetCachedValueAsync(string key)
{
if (_cache.TryGetValue(key, out var value))
return new ValueTask<int>(value); // Synchronous completion
return GetValueFromDatabaseAsync(key); // Asynchronous completion
}
3. LINQ İpuçları
Performanslı LINQ Kullanımı
// Yavaş - multiple enumeration
var numbers = GetNumbers();
var evenCount = numbers.Where(x => x % 2 == 0).Count();
var evenSum = numbers.Where(x => x % 2 == 0).Sum();
// Hızlı - single enumeration
var evenNumbers = GetNumbers().Where(x => x % 2 == 0).ToList();
var evenCount = evenNumbers.Count;
var evenSum = evenNumbers.Sum();
Useful LINQ Extensions
public static class LinqExtensions
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source)
where T : class
{
return source.Where(x => x != null)!;
}
public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> source)
{
return source.Select((item, index) => (item, index));
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
}
// Kullanım
var names = new[] { "John", null, "Jane", null };
var validNames = names.WhereNotNull().WithIndex();
4. Exception Handling
Custom Exceptions
public class BusinessException : Exception
{
public string ErrorCode { get; }
public object? Details { get; }
public BusinessException(string message, string errorCode, object? details = null)
: base(message)
{
ErrorCode = errorCode;
Details = details;
}
}
// Usage
if (user.Balance < amount)
{
throw new BusinessException(
"Insufficient balance",
"INSUFFICIENT_BALANCE",
new { CurrentBalance = user.Balance, RequestedAmount = amount }
);
}
Global Exception Handler
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "An unhandled exception occurred");
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
var response = exception switch
{
BusinessException businessEx => new {
StatusCode = 400,
Message = businessEx.Message,
ErrorCode = businessEx.ErrorCode
},
NotFoundException => new {
StatusCode = 404,
Message = "Resource not found"
},
_ => new {
StatusCode = 500,
Message = "An internal server error occurred"
}
};
context.Response.StatusCode = response.StatusCode;
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
5. Dependency Injection Patterns
Service Lifetimes
// Startup.cs veya Program.cs
services.AddSingleton<IConfigurationService, ConfigurationService>();
services.AddScoped<IUserService, UserService>();
services.AddTransient<IEmailService, EmailService>();
// Factory Pattern
services.AddScoped<IServiceFactory, ServiceFactory>();
services.AddScoped<Func<ServiceType, IBaseService>>(provider => serviceType =>
{
return serviceType switch
{
ServiceType.Email => provider.GetService<IEmailService>(),
ServiceType.Sms => provider.GetService<ISmsService>(),
_ => throw new ArgumentException($"Unknown service type: {serviceType}")
};
});
Options Pattern
public class EmailSettings
{
public string SmtpServer { get; set; } = string.Empty;
public int Port { get; set; }
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
// Registration
services.Configure<EmailSettings>(configuration.GetSection("EmailSettings"));
// Usage
public class EmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> options)
{
_settings = options.Value;
}
}
6. Testing İpuçları
Unit Test Best Practices
[TestClass]
public class UserServiceTests
{
private Mock<IUserRepository> _userRepositoryMock;
private UserService _userService;
[TestInitialize]
public void Setup()
{
_userRepositoryMock = new Mock<IUserRepository>();
_userService = new UserService(_userRepositoryMock.Object);
}
[TestMethod]
public async Task GetUserAsync_ValidId_ReturnsUser()
{
// Arrange
var userId = 1;
var expectedUser = new User { Id = userId, Name = "John" };
_userRepositoryMock
.Setup(x => x.GetByIdAsync(userId))
.ReturnsAsync(expectedUser);
// Act
var result = await _userService.GetUserAsync(userId);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedUser.Name, result.Name);
_userRepositoryMock.Verify(x => x.GetByIdAsync(userId), Times.Once);
}
}
Integration Tests
[TestClass]
public class UserControllerIntegrationTests
{
private WebApplicationFactory<Program> _factory;
private HttpClient _client;
[TestInitialize]
public void Setup()
{
_factory = new WebApplicationFactory<Program>();
_client = _factory.CreateClient();
}
[TestMethod]
public async Task GetUser_ValidId_ReturnsUser()
{
// Arrange
var userId = 1;
// Act
var response = await _client.GetAsync($"/api/users/{userId}");
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var user = JsonSerializer.Deserialize<User>(content);
Assert.IsNotNull(user);
}
}
7. Memory Management
IDisposable Pattern
public class ResourceManager : IDisposable
{
private bool _disposed = false;
private readonly FileStream _fileStream;
private readonly Timer _timer;
public ResourceManager(string filePath)
{
_fileStream = new FileStream(filePath, FileMode.Open);
_timer = new Timer(TimerCallback, null, 0, 1000);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_fileStream?.Dispose();
_timer?.Dispose();
}
_disposed = true;
}
}
~ResourceManager()
{
Dispose(false);
}
}
Using Statements
// Traditional using
using (var stream = new FileStream("file.txt", FileMode.Open))
{
// Process file
}
// Using declaration (C# 8.0+)
using var stream = new FileStream("file.txt", FileMode.Open);
// Stream automatically disposed at end of scope
8. Configuration ve Environment
Structured Configuration
public class ApplicationSettings
{
public DatabaseSettings Database { get; set; } = new();
public EmailSettings Email { get; set; } = new();
public ApiSettings Api { get; set; } = new();
}
public class DatabaseSettings
{
public string ConnectionString { get; set; } = string.Empty;
public int CommandTimeout { get; set; } = 30;
}
// appsettings.json
{
"ApplicationSettings": {
"Database": {
"ConnectionString": "Server=localhost;Database=MyDb;",
"CommandTimeout": 60
},
"Email": {
"SmtpServer": "smtp.gmail.com",
"Port": 587
}
}
}
Sonuç
Bu ipuçları, C# ile daha verimli ve maintainable kod yazmanızı sağlayacak. Özellikle:
- Modern C# özelliklerini kullanarak kodu daha okunabilir hale getirin
- Performans optimizasyonlarını ihmal etmeyin
- LINQ'u doğru şekilde kullanın
- Exception handling stratejinizi belirleyin
- Dependency injection pattern'larını öğrenin
- Testing kültürünü benimseyin
- Memory management konusunda dikkatli olun
Bu teknikleri projelerinizde uyguladığınızda, kodunuzun kalitesinde büyük bir artış göreceksiniz.
Projenizi Hayata Geçirelim mi?
Bu yazıda bahsettiğimiz teknolojilerle işletmenizi büyütmek istiyorsanız, uzman ekibimizle tanışın ve ücretsiz danışmanlık alın.



