Skip to main content
Stereotypes are metadata annotations applied to design elements in Intent Architect. The stereotypes API provides extension methods for querying stereotypes and accessing their property values.

IStereotype Interface

Represents a stereotype applied to a metadata element.
Name
string
The name of the stereotype
DefinitionId
string
Unique identifier for the stereotype definition
Properties
IEnumerable<IStereotypeProperty>
Collection of stereotype properties

IHasStereotypes Interface

Interface implemented by elements that can have stereotypes applied.
Stereotypes
IEnumerable<IStereotype>
Collection of applied stereotypes

StereotypeExtensions

Extension methods for working with stereotypes and their properties.

Querying Stereotypes

HasStereotype

Check if an element has a specific stereotype
bool HasStereotype(this IHasStereotypes model, string stereotypeNameOrId)
model
IHasStereotypes
The element to check
stereotypeNameOrId
string
Stereotype name or definition ID to search for
bool
True if the stereotype is present, false otherwise

GetStereotype

Retrieve a single stereotype by name or ID. Throws if multiple stereotypes match.
IStereotype GetStereotype(this IHasStereotypes model, string stereotypeNameOrId)
model
IHasStereotypes
The element containing the stereotype
stereotypeNameOrId
string
Stereotype name or definition ID
IStereotype
The matching stereotype, or null if not found

GetStereotypes

Retrieve multiple stereotypes with the same name or ID
IReadOnlyCollection<IStereotype> GetStereotypes(
    this IHasStereotypes model,
    string stereotypeNameOrId)
model
IHasStereotypes
The element containing stereotypes
stereotypeNameOrId
string
Stereotype name or definition ID
IReadOnlyCollection<IStereotype>
Collection of matching stereotypes

Accessing Properties

GetStereotypeProperty

Retrieve a typed property value from a stereotype
T GetStereotypeProperty<T>(
    this IHasStereotypes model,
    string stereotypeName,
    string propertyName,
    T defaultIfNotFound = default)
model
IHasStereotypes
Element with the stereotype
stereotypeName
string
Name of the stereotype
propertyName
string
Name of the property to retrieve
defaultIfNotFound
T
default:"default"
Value to return if property is not found
The property value, converted to type T

GetProperty

Retrieve a property value directly from an IStereotype instance
T GetProperty<T>(
    this IStereotype stereotype,
    string propertyName,
    T defaultIfNotFound = default)
stereotype
IStereotype
The stereotype instance
propertyName
string
Name of the property
defaultIfNotFound
T
default:"default"
Default value if property not found
The property value, type-converted to T

Usage Examples

Checking for Stereotypes

// Check if element has specific stereotype
if (model.HasStereotype("REST"))
{
    // Element is marked with REST stereotype
}

// Check using definition ID
if (model.HasStereotype("12345678-1234-1234-1234-123456789abc"))
{
    // Stereotype present
}

Reading Stereotype Properties

// Get string property
var httpVerb = model.GetStereotypeProperty<string>("REST", "Verb", "GET");

// Get boolean property
var isAsync = model.GetStereotypeProperty<bool>("Async", "Enabled", false);

// Get integer property
var maxRetries = model.GetStereotypeProperty<int>("Retry", "MaxAttempts", 3);

// Get nullable property
var timeout = model.GetStereotypeProperty<int?>("Timeout", "Seconds");

Working with Multiple Stereotypes

// Get all stereotypes with same name
var validationStereotypes = model.GetStereotypes("Validation");

foreach (var stereotype in validationStereotypes)
{
    var rule = stereotype.GetProperty<string>("Rule");
    var message = stereotype.GetProperty<string>("ErrorMessage");
    // Apply validation rule
}

Type-Safe Stereotype Access

public static class RestStereotypeExtensions
{
    private const string StereotypeName = "REST";

    public static bool HasREST(this IHasStereotypes model)
    {
        return model.HasStereotype(StereotypeName);
    }

    public static string GetHttpVerb(this IHasStereotypes model)
    {
        return model.GetStereotypeProperty<string>(StereotypeName, "Verb", "GET");
    }

    public static string GetRoute(this IHasStereotypes model)
    {
        return model.GetStereotypeProperty<string>(StereotypeName, "Route");
    }

    public static int GetTimeout(this IHasStereotypes model)
    {
        return model.GetStereotypeProperty<int>(StereotypeName, "Timeout", 30);
    }
}

// Usage
if (operation.HasREST())
{
    var verb = operation.GetHttpVerb();
    var route = operation.GetRoute();
    var timeout = operation.GetTimeout();
}

Conditional Code Generation

public string GenerateMethod(OperationModel operation)
{
    var sb = new StringBuilder();

    // Add async modifier if stereotype present
    if (operation.HasStereotype("Async"))
    {
        sb.Append("async ");
    }

    sb.Append($"public {operation.ReturnType} {operation.Name}(");

    // Add parameters with validation
    var parameters = operation.Parameters
        .Select(p =>
        {
            var param = $"{p.Type} {p.Name}";

            // Check for validation stereotypes
            if (p.HasStereotype("Required"))
            {
                param = $"[Required] {param}";
            }

            if (p.HasStereotype("Range"))
            {
                var min = p.GetStereotypeProperty<int>("Range", "Min");
                var max = p.GetStereotypeProperty<int>("Range", "Max");
                param = $"[Range({min}, {max})] {param}";
            }

            return param;
        });

    sb.Append(string.Join(", ", parameters));
    sb.AppendLine(")");

    return sb.ToString();
}

Property Type Conversion

The stereotype property methods automatically convert values to the requested type:
// String to int
var port = model.GetStereotypeProperty<int>("Config", "Port", 8080);

// String to bool
var enabled = model.GetStereotypeProperty<bool>("Feature", "Enabled", true);

// String to enum
var level = model.GetStereotypeProperty<LogLevel>("Logging", "Level", LogLevel.Info);

// Nullable types
var maxSize = model.GetStereotypeProperty<int?>("Limit", "MaxSize");
if (maxSize.HasValue)
{
    // Use maxSize.Value
}

Error Handling

try
{
    var value = model.GetStereotypeProperty<string>("Config", "Value");
}
catch (Exception e)
{
    // Thrown if:
    // - Multiple stereotypes with same name exist
    // - Type conversion fails
    // - Element access throws exception
}

// Safe alternative with default value
var safeValue = model.GetStereotypeProperty<string>("Config", "Value", "default");

Implementation Reference

StereotypeExtensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Intent.Metadata.Models;

namespace Intent.Modules.Common
{
    /// <summary>
    /// Extension methods for <see cref="IStereotype"/> and <see cref="IHasStereotypes"/>.
    /// </summary>
    public static class StereotypeExtensions
    {
        /// <summary>
        /// Retrieve the value of the property with the provided <paramref name="propertyName"/>
        /// on the provided <paramref name="stereotypeName"/> on the provided <paramref name="model"/>.
        /// </summary>
        public static T GetStereotypeProperty<T>(
            this IHasStereotypes model,
            string stereotypeName,
            string propertyName,
            T defaultIfNotFound = default)
        {
            try
            {
                return model.GetStereotype(stereotypeName)
                    .GetProperty(propertyName, defaultIfNotFound);
            }
            catch (Exception e)
            {
                throw new Exception(
                    $"Failed to get stereotype property for element [{model}]", e);
            }
        }

        /// <summary>
        /// Lookup only one stereotype with a given name. If more than one is found
        /// with the same name an exception is thrown.
        /// </summary>
        public static IStereotype GetStereotype(
            this IHasStereotypes model,
            string stereotypeNameOrId)
        {
            var stereotypes = model.Stereotypes
                .Where(x => x.Name == stereotypeNameOrId ||
                           x.DefinitionId == stereotypeNameOrId)
                .ToArray();

            if (stereotypes.Length > 1)
            {
                throw new Exception(
                    model is IMetadataModel metadataModel
                        ? $"More than one stereotype found with the name " +
                          $"'{stereotypeNameOrId}' on element with ID {metadataModel.Id}"
                        : $"More than one stereotype found with the name " +
                          $"'{stereotypeNameOrId}'");
            }

            return stereotypes.SingleOrDefault();
        }

        /// <summary>
        /// Look up multiple stereotypes by the same name or definitionId.
        /// </summary>
        public static IReadOnlyCollection<IStereotype> GetStereotypes(
            this IHasStereotypes model,
            string stereotypeNameOrId)
        {
            return model.Stereotypes
                .Where(p => p.Name == stereotypeNameOrId ||
                           p.DefinitionId == stereotypeNameOrId)
                .ToArray();
        }

        /// <summary>
        /// Used to query whether or not a stereotype with a particular name or
        /// definition Id is present.
        /// </summary>
        public static bool HasStereotype(
            this IHasStereotypes model,
            string stereotypeNameOrId)
        {
            return model.Stereotypes.Any(x => x.Name == stereotypeNameOrId ||
                                             x.DefinitionId == stereotypeNameOrId);
        }
    }
}

Best Practices

Create Extension Methods

Wrap stereotype access in type-safe extension methods specific to your stereotypes

Use Default Values

Always provide sensible default values for optional stereotype properties

Handle Missing Stereotypes

Use HasStereotype before accessing properties, or rely on default values

Document Property Names

Keep constants for stereotype and property names to avoid typos

See Also

Build docs developers (and LLMs) love