Socket
Book a DemoInstallSign in
Socket

Structura

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Structura

A powerful .NET library that converts anonymous types and EF Core projections to strongly-typed types using source generators. Features include property addition/exclusion/type conversion, smart converters, and support for Records, Classes, and Structs with comprehensive testing coverage.

1.0.0
Source
nugetNuGet
Version published
Maintainers
1
Created
Source

Structura

Fluent API-based Source Generator Type Manipulation Library

Structura is a flexible type generation library that converts anonymous types and EF Core projection results to strongly-typed types, with the ability to add, exclude, and change properties.

🚀 Key Features

  • 🎭 Anonymous Type Combination: Combine multiple anonymous types to create new types
  • 🔗 EF Core Projection Support: Automatically convert EF Core Select results to strongly-typed types
  • ➕ Property Addition: Add new properties to existing types (.Add())
  • ➖ Property Exclusion: Exclude sensitive or unnecessary properties (.Exclude())
  • 🔄 Type Conversion: Change existing property types to different types (.ChangeType())
  • 🎯 Smart Converter: Automatically generate extension methods for converting anonymous objects to strong types
  • 🏷️ Multiple Type Generation: Support for Records, Classes, and Structs
  • 🧪 Comprehensive Testing: Stability verified with 100+ unit tests

📦 Installation

dotnet add package Structura

🏗️ Core Features

1. Anonymous Type Combination

Combine multiple anonymous types to create new strongly-typed types.

// Single anonymous type usage
var userInfo = new { Name = "John Doe", Age = 30, Department = "Development" };

TypeCombiner.Combine()
    .With(userInfo)
    .WithName("Employee")
    .AsRecord()
    .Generate();

// Usage: new Generated.Employee("Jane Smith", 25, "Design")

// Multiple anonymous type combination
var personal = new { FirstName = "John", LastName = "Doe" };
var work = new { Company = "TechCorp", Position = "Developer" };

TypeCombiner.Combine()
    .With(personal)
    .With(work)
    .WithName("FullProfile")
    .AsClass()
    .Generate();

2. EF Core Projection Support

Automatically convert EF Core Select results to strongly-typed types.

// EF Core projection query
var userProjection = dbContext.Users
    .Select(u => new { u.Name, u.Email, u.Department })
    .ToList();

// Strong type generation
TypeCombiner.Combine()
    .WithProjection(userProjection)
    .WithName("UserDto")
    .WithConverter()  // 🔥 Enable smart conversion
    .AsRecord()
    .Generate();

// Automatic conversion usage
List<Generated.UserDto> typedUsers = UserDto.FromCollection(userProjection);
Generated.UserDto singleUser = UserDto.FromSingle(userProjection.First());

3. 🎯 Smart Converter (Core Feature!)

The game-changer for EF Core projections! Generates static methods for automatically converting anonymous objects to strongly-typed types.

// Step 1: Generate type with converter enabled
var customerData = dbContext.Orders
    .GroupBy(o => o.CustomerId)
    .Select(g => new {
        CustomerId = g.Key,
        CustomerName = g.First().Customer.Name,
        TotalOrders = g.Count(),
        TotalSpent = g.Sum(o => o.Amount)
    })
    .ToList();

TypeCombiner.Combine()
    .WithProjection(customerData)
    .WithName("CustomerAnalytics")
    .WithConverter()  // 🔥 The magic begins!
    .AsRecord()
    .Generate();

// Step 2: Use conversion methods directly on the generated type
List<Generated.CustomerAnalytics> analytics = CustomerAnalytics.FromCollection(customerData);
Generated.CustomerAnalytics single = CustomerAnalytics.FromSingle(customerData.First());

// Strongly-typed anonymous objects are also convertible
var anonymousData = new[] {
    new { CustomerId = 1, CustomerName = "John Doe", TotalOrders = 5, TotalSpent = 150000m },
    new { CustomerId = 2, CustomerName = "Jane Smith", TotalOrders = 3, TotalSpent = 75000m }
};
List<Generated.CustomerAnalytics> converted = CustomerAnalytics.FromTypedCollection(anonymousData);

4. Property Manipulation Features

Property Addition

// Add new properties to existing types
var userData = new { Name = "John Doe", Email = "john@test.com" };

TypeCombiner.Combine()
    .With(userData)
    .Add("Id", typeof(int))
    .Add("CreatedAt", typeof(DateTime))
    .Add("Metadata", typeof(Dictionary<string, object>))
    .WithName("EnhancedUser")
    .AsClass()
    .Generate();

// Pure Add usage for type creation
TypeCombiner.Combine()
    .Add("Name", typeof(string))
    .Add("Value", typeof(int))
    .Add("IsActive", typeof(bool))
    .WithName("CustomType")
    .AsRecord()
    .Generate();

Property Exclusion

// Exclude sensitive information
var sensitiveData = new { 
    Name = "John Doe", 
    Age = 30, 
    Password = "secret123", 
    Email = "john@test.com" 
};

TypeCombiner.Combine()
    .With(sensitiveData)
    .Exclude("Password")  // Exclude password
    .WithName("SafeUser")
    .AsClass()
    .Generate();

// Multiple property exclusion
TypeCombiner.Combine()
    .With(userData)
    .Exclude("Password")
    .Exclude("InternalId")
    .WithName("PublicData")
    .Generate();

Type Conversion

// Property type conversion
var numericData = new { 
    Id = 1, 
    Price = 100m, 
    Quantity = 5, 
    IsActive = true 
};

TypeCombiner.Combine()
    .With(numericData)
    .ChangeType("Price", typeof(string))    // decimal → string
    .ChangeType("Quantity", typeof(long))   // int → long
    .ChangeType("IsActive", typeof(int))    // bool → int
    .WithName("ConvertedProduct")
    .AsClass()
    .Generate();

5. Complex Operations

All features can be used together.

// EF Core projection + property addition + type conversion + converter
var orderProjection = dbContext.Orders
    .Select(o => new { 
        o.Id, 
        o.CustomerName, 
        o.Amount, 
        o.OrderDate 
    })
    .ToList();

TypeCombiner.Combine()
    .WithProjection(orderProjection)
    .Add("ProcessedAt", typeof(DateTime))           // Property addition
    .Add("Status", typeof(string))                  // Property addition
    .ChangeType("Amount", typeof(string))           // decimal → string
    .Exclude("InternalId")                          // Property exclusion (if exists)
    .WithConverter()                                // Enable smart converter
    .WithName("ProcessedOrder")
    .AsRecord()
    .Generate();

// Complete conversion support
List<Generated.ProcessedOrder> orders = ProcessedOrder.FromCollection(orderProjection);

🏷️ Supported Type Generation

TypeMethodDescriptionConverter Support
Record.AsRecord()Generate immutable record types✅ Full Support
Class.AsClass()Generate mutable class types✅ Full Support
Struct.AsStruct()Generate value type structs✅ Full Support

🎯 Target Frameworks

  • .NET Standard 2.0 and above
  • .NET 9 recommended
  • C# 12.0 syntax support

🚀 Real-World Usage Scenarios

EF Core Integration

// Complex dashboard data generation
var dashboardData = await dbContext.Orders
    .Include(o => o.Customer)
    .GroupBy(o => new { o.CustomerId, o.Customer.Name })
    .Select(g => new {
        CustomerId = g.Key.CustomerId,
        CustomerName = g.Key.Name,
        TotalOrders = g.Count(),
        TotalRevenue = g.Sum(o => o.Amount),
        AverageOrderValue = g.Average(o => o.Amount),
        LastOrderDate = g.Max(o => o.OrderDate)
    })
    .ToListAsync();

// Strongly-typed DTO generation and conversion
TypeCombiner.Combine()
    .WithProjection(dashboardData)
    .Add("GeneratedAt", typeof(DateTime))
    .Add("ReportType", typeof(string))
    .WithName("CustomerDashboard")
    .WithConverter()
    .AsRecord()
    .Generate();

// Immediately available strongly-typed collection
List<Generated.CustomerDashboard> dashboard = CustomerDashboard.FromCollection(dashboardData);

// Complete type safety in business logic
var topCustomers = dashboard
    .Where(c => c.TotalRevenue > 100000)
    .OrderByDescending(c => c.TotalRevenue)
    .Take(10)
    .ToList();

API DTO Generation

// Generate public API DTO from internal entity
var internalUser = new { 
    Id = 1, 
    Name = "John Doe", 
    Email = "john@company.com", 
    Password = "hashed_password", 
    InternalNotes = "Important internal info",
    Salary = 5000000m
};

TypeCombiner.Combine()
    .With(internalUser)
    .Exclude("Password")       // Exclude password
    .Exclude("InternalNotes")  // Exclude internal info
    .Exclude("Salary")         // Exclude salary info
    .Add("PublicId", typeof(Guid))
    .WithConverter()
    .WithName("UserApiDto")
    .AsRecord()
    .Generate();

Data Transformation Pipeline

// Convert external API response to internal format
var externalApiResponse = new[] {
    new { user_id = "123", full_name = "John Doe", email_addr = "john@example.com", is_active = "1" },
    new { user_id = "456", full_name = "Jane Smith", email_addr = "jane@example.com", is_active = "0" }
};

TypeCombiner.Combine()
    .WithProjection(externalApiResponse)
    .ChangeType("user_id", typeof(int))      // string → int
    .ChangeType("is_active", typeof(bool))   // string → bool
    .Add("ImportedAt", typeof(DateTime))
    .WithConverter()
    .WithName("ImportedUser")
    .AsRecord()
    .Generate();

// Type-safe conversion
List<Generated.ImportedUser> users = ImportedUser.FromCollection(externalApiResponse);

🧪 Testing

Running Tests

dotnet test

Comprehensive Test Coverage

Structura is validated with 100+ comprehensive unit tests:

Test CategoryTest CountDescription
Core Features15All basic TypeCombiner API features
Anonymous Types12Anonymous object combination and processing
EF Core Projection18EF Core projection result processing
Variable References8Anonymous type variable analysis
Type Generation Modes6Record, Class, Struct type generation
Edge Cases5Error conditions and boundary cases
Fluent API4Method chaining integrity
Type Safety3Compile-time type validation
Source Generator Integration8Generated type verification
Performance3Large-scale processing and performance
Real-World Scenarios10Production environment use cases
Documented Features12README example code validation
Integration Scenarios15Complex feature combinations
🆕 Converter Extensions20Smart converter functionality
Add/Exclude/ChangeType18Property manipulation features

🎯 Test Results

  • Total Tests: 150+
  • Passed: 150+ ✅
  • Failed: 0
  • Skipped: 0
  • Execution Time: < 3 seconds

📁 Project Structure

Structura/ ├── 📂 Structura/ # Main library │ ├── TypeCombiner.cs # Fluent API entry point │ ├── AnonymousTypeCombinerBuilder.cs # Anonymous type builder │ ├── TypeDefinitions.cs # Core type definitions │ └── StructuraSourceGenerator.cs # Source generator engine ├── 📂 Structura.Test.Console/ # Integration test console │ └── Program.cs # Real usage examples and demos ├── 📂 Structura.Tests/ # Unit test project │ ├── UnitTest.cs # Basic functionality unit tests │ ├── VariableReferenceTests.cs # Variable reference feature tests │ ├── EFCoreProjectionTests.cs # EF Core projection tests │ ├── ConverterExtensionTests.cs # Smart converter tests │ ├── AddFunctionalityTests.cs # Add functionality tests │ ├── ExcludeFunctionalityTests.cs # Exclude functionality tests │ ├── ChangeTypeFunctionalityTests.cs # ChangeType functionality tests │ └── IntegrationTests.cs # Integration and scenario tests └── 📄 README.md # Documentation

📈 Development Status

✅ Completed Features

FeatureStatusDescription
Source Generator Engine100% ✅Complete
Fluent API100% ✅Complete
Anonymous Type Support100% ✅Complete
Variable Reference Analysis100% ✅Complete
EF Core Projection Support100% ✅Complete
Property Add/Exclude/ChangeType100% ✅Complete
Type Conversion100% ✅Record/Class/Struct support
🆕 Smart Converter Extensions100% ✅NEW! Perfect object conversion
Comprehensive Test Suite100% ✅150+ tests passing

🚀 Getting Started

1. Installation

dotnet add package Structura

2. Basic Usage

using Structura;

// Create new type from anonymous types
var userData = new { Name = "John Doe", Age = 30, Email = "john@test.com" };

TypeCombiner.Combine()
    .With(userData)
    .Add("Id", typeof(int))
    .Exclude("InternalData")  // Exclude if exists
    .WithName("User")
    .AsRecord()
    .Generate();

// Use the generated type
var user = new Generated.User("Jane Smith", 25, "jane@test.com", 1001);

3. Advanced Usage with Converter

// EF Core projection conversion
var efResult = dbContext.Products
    .Select(p => new { p.Name, p.Price, p.Category })
    .ToList();

TypeCombiner.Combine()
    .WithProjection(efResult)
    .Add("ProcessedAt", typeof(DateTime))
    .WithConverter()  // 🔥 Enable smart conversion
    .WithName("ProductDto")
    .AsRecord()
    .Generate();

// Immediate conversion available
List<Generated.ProductDto> products = ProductDto.FromCollection(efResult);

🎨 API Reference

TypeCombiner Static Methods

MethodDescriptionReturn Type
Combine()Start with anonymous types onlyAnonymousTypeCombinerBuilder

Fluent Methods

MethodDescriptionChainable
.With(object)Add anonymous type
.WithProjection(IEnumerable<object>)Add EF Core projection
.Add(string, Type)Add property
.Exclude(string)Exclude property
.ChangeType(string, Type)Change property type
.WithConverter()🆕 Enable smart converter extensions
.WithName(string)Set generated type name
.AsRecord()Generate as record
.AsClass()Generate as class
.AsStruct()Generate as struct
.Generate()Execute type generation

🆕 Generated Static Converter Methods

When .WithConverter() is used, the following static methods are automatically generated on the generated type itself:

MethodDescriptionUsage
.FromSingle(object)Convert single objectUserDto.FromSingle(objectItem)
.FromTyped<T>(T)Convert single strongly-typed objectUserDto.FromTyped(anonymousItem)
.FromCollection(IEnumerable<object>)Convert object collectionUserDto.FromCollection(objectList)
.FromTypedCollection<T>(IEnumerable<T>)Convert strongly-typed collectionUserDto.FromTypedCollection(anonymousList)

🤝 Contributing

Issues and pull requests are welcome!

📄 License

MIT License

Structura - Simplify type manipulation with smart conversion! 🚀

Keywords

source-generator

FAQs

Package last updated on 12 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.