Class Diagrams
The Create methods support creating mermaid class diagrams
Manual
There is a programmatic API that allows for custom class diagrams from code
var result = ClassDiagramBuilder.Create(
[
new ClassModel(
"Animal",
Members:
[
new MemberModel("age", MemberVisibility.Public, TypeName: "int"),
new MemberModel("gender", MemberVisibility.Public, TypeName: "String"),
new MemberModel("isMammal", MemberVisibility.Public, Parameters: []),
new MemberModel("mate", MemberVisibility.Public, Parameters: []),
],
Notes: "can fly\ncan swim\ncan dive\ncan help in debugging"
),
new ClassModel(
"Duck",
Members:
[
new MemberModel("beakColor", MemberVisibility.Public, TypeName: "String"),
new MemberModel("swim", MemberVisibility.Public, Parameters: []),
new MemberModel("quack", MemberVisibility.Public, Parameters: []),
]
),
new ClassModel(
"Fish",
Members:
[
new MemberModel("sizeInFeet", MemberVisibility.Private, TypeName: "int"),
new MemberModel("canEat", MemberVisibility.Public, Parameters: []),
]
),
new ClassModel(
"Zebra",
Members:
[
new MemberModel("is_wild", MemberVisibility.Public, TypeName: "bool"),
new MemberModel("run", MemberVisibility.Public, Parameters: []),
]
),
],
[
new RelationshipModel("Duck", "Animal", RelationshipType.Inheritence),
new RelationshipModel("Fish", "Animal", RelationshipType.Inheritence),
new RelationshipModel("Zebra", "Animal", RelationshipType.Inheritence),
]
);
result.SaveResults();
classDiagram
`Animal` <|-- `Duck`
`Animal` <|-- `Fish`
`Animal` <|-- `Zebra`
note for `Animal` "can fly
can swim
can dive
can help in debugging"
class `Animal`
`Animal` : +int age
`Animal` : +String gender
`Animal` : +isMammal()
`Animal` : +mate()
class `Duck`
`Duck` : +String beakColor
`Duck` : +swim()
`Duck` : +quack()
class `Fish`
`Fish` : -int sizeInFeet
`Fish` : +canEat()
class `Zebra`
`Zebra` : +bool is_wild
`Zebra` : +run()
From Types
Given a set of Types
it can generate a class diagram and automatic
relationships,
interface ILifeform
{
void Breethe();
}
interface IAnimal : ILifeform
{
void Eat();
string Call();
}
abstract class Bird : IAnimal
{
public void Eat() => throw new NotSupportedException();
public abstract string Call();
public void Breethe() => throw new NotSupportedException();
}
class Duck : Bird
{
public override string Call() => "Quack Quack";
}
class Swan : Bird
{
public override string Call() => "Honk Honk";
}
class Dog : IAnimal
{
public void Eat() => throw new NotSupportedException();
public string Call() => "Woof Woof";
public void Breethe() => throw new NotSupportedException();
}
[Fact(DisplayName = "Create a ClassDiagram with inheritance")]
public static async Task Case6()
{
var result = ClassDiagramBuilder.Create(
[
typeof(ILifeform),
typeof(IAnimal),
typeof(Bird),
typeof(Swan),
typeof(Duck),
typeof(Dog),
]
);
result.SaveResults();
await Verify(result).UseDirectory("__snapshots__");
}
classDiagram
`ClassDiagramTests.IAnimal` <|-- `ClassDiagramTests.Bird`
`ClassDiagramTests.IAnimal` <|-- `ClassDiagramTests.Dog`
`ClassDiagramTests.Bird` <|-- `ClassDiagramTests.Duck`
`ClassDiagramTests.ILifeform` <|-- `ClassDiagramTests.IAnimal`
`ClassDiagramTests.Bird` <|-- `ClassDiagramTests.Swan`
class `ClassDiagramTests.Bird`
<<abstract>> `ClassDiagramTests.Bird`
`ClassDiagramTests.Bird` : +Breethe() void
`ClassDiagramTests.Bird` : +Call() string*
`ClassDiagramTests.Bird` : +Eat() void
`ClassDiagramTests.Bird` : +Equals(object obj) bool
`ClassDiagramTests.Bird` : -Finalize() void
`ClassDiagramTests.Bird` : +GetHashCode() int
`ClassDiagramTests.Bird` : +GetType() Type
`ClassDiagramTests.Bird` : -MemberwiseClone() object
`ClassDiagramTests.Bird` : +ToString() string
class `ClassDiagramTests.Dog`
`ClassDiagramTests.Dog` : +Breethe() void
`ClassDiagramTests.Dog` : +Call() string
`ClassDiagramTests.Dog` : +Eat() void
`ClassDiagramTests.Dog` : +Equals(object obj) bool
`ClassDiagramTests.Dog` : -Finalize() void
`ClassDiagramTests.Dog` : +GetHashCode() int
`ClassDiagramTests.Dog` : +GetType() Type
`ClassDiagramTests.Dog` : -MemberwiseClone() object
`ClassDiagramTests.Dog` : +ToString() string
class `ClassDiagramTests.Duck`
`ClassDiagramTests.Duck` : +Breethe() void
`ClassDiagramTests.Duck` : +Call() string
`ClassDiagramTests.Duck` : +Eat() void
`ClassDiagramTests.Duck` : +Equals(object obj) bool
`ClassDiagramTests.Duck` : -Finalize() void
`ClassDiagramTests.Duck` : +GetHashCode() int
`ClassDiagramTests.Duck` : +GetType() Type
`ClassDiagramTests.Duck` : -MemberwiseClone() object
`ClassDiagramTests.Duck` : +ToString() string
class `ClassDiagramTests.IAnimal`
<<interface>> `ClassDiagramTests.IAnimal`
`ClassDiagramTests.IAnimal` : +Call() string*
`ClassDiagramTests.IAnimal` : +Eat() void*
class `ClassDiagramTests.ILifeform`
<<interface>> `ClassDiagramTests.ILifeform`
`ClassDiagramTests.ILifeform` : +Breethe() void*
class `ClassDiagramTests.Swan`
`ClassDiagramTests.Swan` : +Breethe() void
`ClassDiagramTests.Swan` : +Call() string
`ClassDiagramTests.Swan` : +Eat() void
`ClassDiagramTests.Swan` : +Equals(object obj) bool
`ClassDiagramTests.Swan` : -Finalize() void
`ClassDiagramTests.Swan` : +GetHashCode() int
`ClassDiagramTests.Swan` : +GetType() Type
`ClassDiagramTests.Swan` : -MemberwiseClone() object
`ClassDiagramTests.Swan` : +ToString() string
From a single Type
Given a single Type
it can build a full class diagram for that Type
and all
related Types
public class CustomList : List<int> { }
[Fact(DisplayName = "Create a ClassDiagram from a type exploded")]
public static async Task Case10()
{
var result = ClassDiagramBuilder.Create(
typeof(List<int>),
assemblyTransformer: assemblies => assemblies.Append(typeof(ClassDiagramTests).Assembly)
);
classDiagram
`List<int>` <|-- `ClassDiagramTests.CustomList`
`IEnumerable` <|-- `ICollection`
`IEnumerable` <|-- `ICollection<int>`
`IEnumerable<int>` <|-- `ICollection<int>`
`IEnumerable` <|-- `IEnumerable<int>`
`ICollection` <|-- `IList`
`IEnumerable` <|-- `IList`
`ICollection<int>` <|-- `IList<int>`
`IEnumerable` <|-- `IList<int>`
`IEnumerable<int>` <|-- `IList<int>`
`IEnumerable` <|-- `IReadOnlyCollection<int>`
`IEnumerable<int>` <|-- `IReadOnlyCollection<int>`
`IEnumerable` <|-- `IReadOnlyList<int>`
`IEnumerable<int>` <|-- `IReadOnlyList<int>`
`IReadOnlyCollection<int>` <|-- `IReadOnlyList<int>`
`IList` <|-- `List<int>`
`IList<int>` <|-- `List<int>`
`IReadOnlyList<int>` <|-- `List<int>`
`List<int>` "1" <-- "1" `ClassDiagramTests.CustomList` : FindAll
`List<int>` "1" <-- "1" `ClassDiagramTests.CustomList` : GetRange
`List<int>` "1" <-- "1" `ClassDiagramTests.CustomList` : Slice
`List<int>` "1" <-- "1" `List<int>` : FindAll
`List<int>` "1" <-- "1" `List<int>` : GetRange
`List<int>` "1" <-- "1" `List<int>` : Slice
class `ClassDiagramTests.CustomList`
`ClassDiagramTests.CustomList` : +int Capacity
`ClassDiagramTests.CustomList` : +int Count
`ClassDiagramTests.CustomList` : +int Item
`ClassDiagramTests.CustomList` : -int[] _items
`ClassDiagramTests.CustomList` : -int _size
`ClassDiagramTests.CustomList` : -int _version
`ClassDiagramTests.CustomList` : +Add(int item) void
`ClassDiagramTests.CustomList` : +AddRange(IEnumerable<int> collection) void
`ClassDiagramTests.CustomList` : +AsReadOnly() ReadOnlyCollection<int>
`ClassDiagramTests.CustomList` : +BinarySearch(int index, int count, int item, IComparer<int> comparer) int
`ClassDiagramTests.CustomList` : +BinarySearch(int item) int
`ClassDiagramTests.CustomList` : +BinarySearch(int item, IComparer<int> comparer) int
`ClassDiagramTests.CustomList` : +Clear() void
`ClassDiagramTests.CustomList` : +Contains(int item) bool
`ClassDiagramTests.CustomList` : +ConvertAll(Converter<int, TOutput> converter) List<TOutput>
`ClassDiagramTests.CustomList` : +CopyTo(int[] array) void
`ClassDiagramTests.CustomList` : +CopyTo(int index, int[] array, int arrayIndex, int count) void
`ClassDiagramTests.CustomList` : +CopyTo(int[] array, int arrayIndex) void
`ClassDiagramTests.CustomList` : +EnsureCapacity(int capacity) int
`ClassDiagramTests.CustomList` : +Equals(object obj) bool
`ClassDiagramTests.CustomList` : +Exists(Predicate<int> match) bool
`ClassDiagramTests.CustomList` : -Finalize() void
`ClassDiagramTests.CustomList` : +Find(Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindAll(Predicate<int> match) List<int>
`ClassDiagramTests.CustomList` : +FindIndex(Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindIndex(int startIndex, Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindIndex(int startIndex, int count, Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindLast(Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindLastIndex(Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindLastIndex(int startIndex, Predicate<int> match) int
`ClassDiagramTests.CustomList` : +FindLastIndex(int startIndex, int count, Predicate<int> match) int
`ClassDiagramTests.CustomList` : +ForEach(Action<int> action) void
`ClassDiagramTests.CustomList` : +GetEnumerator() List<int>.Enumerator
`ClassDiagramTests.CustomList` : +GetHashCode() int
`ClassDiagramTests.CustomList` : +GetRange(int index, int count) List<int>
`ClassDiagramTests.CustomList` : +GetType() Type
`ClassDiagramTests.CustomList` : -Grow(int capacity) void
`ClassDiagramTests.CustomList` : +IndexOf(int item) int
`ClassDiagramTests.CustomList` : +IndexOf(int item, int index) int
`ClassDiagramTests.CustomList` : +IndexOf(int item, int index, int count) int
`ClassDiagramTests.CustomList` : +Insert(int index, int item) void
`ClassDiagramTests.CustomList` : +InsertRange(int index, IEnumerable<int> collection) void
`ClassDiagramTests.CustomList` : +LastIndexOf(int item) int
`ClassDiagramTests.CustomList` : +LastIndexOf(int item, int index) int
`ClassDiagramTests.CustomList` : +LastIndexOf(int item, int index, int count) int
`ClassDiagramTests.CustomList` : -MemberwiseClone() object
`ClassDiagramTests.CustomList` : +Remove(int item) bool
`ClassDiagramTests.CustomList` : +RemoveAll(Predicate<int> match) int
`ClassDiagramTests.CustomList` : +RemoveAt(int index) void
`ClassDiagramTests.CustomList` : +RemoveRange(int index, int count) void
`ClassDiagramTests.CustomList` : +Reverse() void
`ClassDiagramTests.CustomList` : +Reverse(int index, int count) void
`ClassDiagramTests.CustomList` : +Slice(int start, int length) List<int>
`ClassDiagramTests.CustomList` : +Sort() void
`ClassDiagramTests.CustomList` : +Sort(IComparer<int> comparer) void
`ClassDiagramTests.CustomList` : +Sort(int index, int count, IComparer<int> comparer) void
`ClassDiagramTests.CustomList` : +Sort(Comparison<int> comparison) void
`ClassDiagramTests.CustomList` : -System.Collections.Generic.IEnumerable<T>.GetEnumerator() IEnumerator<int>
`ClassDiagramTests.CustomList` : -System.Collections.ICollection.CopyTo(Array array, int arrayIndex) void
`ClassDiagramTests.CustomList` : -System.Collections.IEnumerable.GetEnumerator() IEnumerator
`ClassDiagramTests.CustomList` : -System.Collections.IList.Add(object item) int
`ClassDiagramTests.CustomList` : -System.Collections.IList.Contains(object item) bool
`ClassDiagramTests.CustomList` : -System.Collections.IList.IndexOf(object item) int
`ClassDiagramTests.CustomList` : -System.Collections.IList.Insert(int index, object item) void
`ClassDiagramTests.CustomList` : -System.Collections.IList.Remove(object item) void
`ClassDiagramTests.CustomList` : +ToArray() int[]
`ClassDiagramTests.CustomList` : +ToString() string
`ClassDiagramTests.CustomList` : +TrimExcess() void
`ClassDiagramTests.CustomList` : +TrueForAll(Predicate<int> match) bool
class `ICollection`
<<interface>> `ICollection`
`ICollection` : +int Count
`ICollection` : +bool IsSynchronized
`ICollection` : +object SyncRoot
`ICollection` : +CopyTo(Array array, int index) void*
class `ICollection<int>`
<<interface>> `ICollection<int>`
`ICollection<int>` : +int Count
`ICollection<int>` : +bool IsReadOnly
`ICollection<int>` : +Add(int item) void*
`ICollection<int>` : +Clear() void*
`ICollection<int>` : +Contains(int item) bool*
`ICollection<int>` : +CopyTo(int[] array, int arrayIndex) void*
`ICollection<int>` : +Remove(int item) bool*
class `IEnumerable`
<<interface>> `IEnumerable`
`IEnumerable` : +GetEnumerator() IEnumerator*
class `IEnumerable<int>`
<<interface>> `IEnumerable<int>`
`IEnumerable<int>` : +GetEnumerator() IEnumerator<int>*
class `IList`
<<interface>> `IList`
`IList` : +bool IsFixedSize
`IList` : +bool IsReadOnly
`IList` : +object Item*
`IList` : +Add(object value) int*
`IList` : +Clear() void*
`IList` : +Contains(object value) bool*
`IList` : +IndexOf(object value) int*
`IList` : +Insert(int index, object value) void*
`IList` : +Remove(object value) void*
`IList` : +RemoveAt(int index) void*
class `IList<int>`
<<interface>> `IList<int>`
`IList<int>` : +int Item*
`IList<int>` : +IndexOf(int item) int*
`IList<int>` : +Insert(int index, int item) void*
`IList<int>` : +RemoveAt(int index) void*
class `IReadOnlyCollection<int>`
<<interface>> `IReadOnlyCollection<int>`
`IReadOnlyCollection<int>` : +int Count
class `IReadOnlyList<int>`
<<interface>> `IReadOnlyList<int>`
`IReadOnlyList<int>` : +int Item
class `List<int>`
`List<int>` : +int Capacity
`List<int>` : +int Count
`List<int>` : +int Item
`List<int>` : -bool System.Collections.Generic.ICollection<T>.IsReadOnly
`List<int>` : -bool System.Collections.ICollection.IsSynchronized
`List<int>` : -object System.Collections.ICollection.SyncRoot
`List<int>` : -bool System.Collections.IList.IsFixedSize
`List<int>` : -bool System.Collections.IList.IsReadOnly
`List<int>` : -object System.Collections.IList.Item
`List<int>` : -int[] s_emptyArray$
`List<int>` : -int[] _items
`List<int>` : -int _size
`List<int>` : -int _version
`List<int>` : +Add(int item) void
`List<int>` : +AddRange(IEnumerable<int> collection) void
`List<int>` : -AddWithResize(int item) void
`List<int>` : +AsReadOnly() ReadOnlyCollection<int>
`List<int>` : +BinarySearch(int index, int count, int item, IComparer<int> comparer) int
`List<int>` : +BinarySearch(int item) int
`List<int>` : +BinarySearch(int item, IComparer<int> comparer) int
`List<int>` : +Clear() void
`List<int>` : +Contains(int item) bool
`List<int>` : +ConvertAll(Converter<int, TOutput> converter) List<TOutput>
`List<int>` : +CopyTo(int[] array) void
`List<int>` : +CopyTo(int index, int[] array, int arrayIndex, int count) void
`List<int>` : +CopyTo(int[] array, int arrayIndex) void
`List<int>` : +EnsureCapacity(int capacity) int
`List<int>` : +Equals(object obj) bool
`List<int>` : +Exists(Predicate<int> match) bool
`List<int>` : -Finalize() void
`List<int>` : +Find(Predicate<int> match) int
`List<int>` : +FindAll(Predicate<int> match) List<int>
`List<int>` : +FindIndex(Predicate<int> match) int
`List<int>` : +FindIndex(int startIndex, Predicate<int> match) int
`List<int>` : +FindIndex(int startIndex, int count, Predicate<int> match) int
`List<int>` : +FindLast(Predicate<int> match) int
`List<int>` : +FindLastIndex(Predicate<int> match) int
`List<int>` : +FindLastIndex(int startIndex, Predicate<int> match) int
`List<int>` : +FindLastIndex(int startIndex, int count, Predicate<int> match) int
`List<int>` : +ForEach(Action<int> action) void
`List<int>` : +GetEnumerator() List<int>.Enumerator
`List<int>` : +GetHashCode() int
`List<int>` : +GetRange(int index, int count) List<int>
`List<int>` : +GetType() Type
`List<int>` : -Grow(int capacity) void
`List<int>` : +IndexOf(int item) int
`List<int>` : +IndexOf(int item, int index) int
`List<int>` : +IndexOf(int item, int index, int count) int
`List<int>` : +Insert(int index, int item) void
`List<int>` : +InsertRange(int index, IEnumerable<int> collection) void
`List<int>` : -IsCompatibleObject(object value) bool$
`List<int>` : +LastIndexOf(int item) int
`List<int>` : +LastIndexOf(int item, int index) int
`List<int>` : +LastIndexOf(int item, int index, int count) int
`List<int>` : -MemberwiseClone() object
`List<int>` : +Remove(int item) bool
`List<int>` : +RemoveAll(Predicate<int> match) int
`List<int>` : +RemoveAt(int index) void
`List<int>` : +RemoveRange(int index, int count) void
`List<int>` : +Reverse() void
`List<int>` : +Reverse(int index, int count) void
`List<int>` : +Slice(int start, int length) List<int>
`List<int>` : +Sort() void
`List<int>` : +Sort(IComparer<int> comparer) void
`List<int>` : +Sort(int index, int count, IComparer<int> comparer) void
`List<int>` : +Sort(Comparison<int> comparison) void
`List<int>` : -System.Collections.Generic.IEnumerable<T>.GetEnumerator() IEnumerator<int>
`List<int>` : -System.Collections.ICollection.CopyTo(Array array, int arrayIndex) void
`List<int>` : -System.Collections.IEnumerable.GetEnumerator() IEnumerator
`List<int>` : -System.Collections.IList.Add(object item) int
`List<int>` : -System.Collections.IList.Contains(object item) bool
`List<int>` : -System.Collections.IList.IndexOf(object item) int
`List<int>` : -System.Collections.IList.Insert(int index, object item) void
`List<int>` : -System.Collections.IList.Remove(object item) void
`List<int>` : +ToArray() int[]
`List<int>` : +ToString() string
`List<int>` : +TrimExcess() void
`List<int>` : +TrueForAll(Predicate<int> match) bool
From Assemblies
Given a set of Assemblies
it can build a class diagram from all exposed types
var result = ClassDiagramBuilder.Create(
[typeof(ClassDiagramBuilder).Assembly],
type =>
type.IsPublic
&& !type.Name.Contains("ClassDiagramBuilder")
&& !type.Name.Contains("ModelTransformer")
&& !type.Name.Contains("ResultExtensions"),
// filter out all non-public members
classModelTransformer: classes =>
classes.Select(@class =>
@class with
{
Members = @class.Members?.Where(member =>
member.Visibility is MemberVisibility.Public
),
}
)
);
result.SaveResults();
classDiagram
`MemberModel` "*" <-- "1" `ClassModel` : Members
`MemberVisibility` "1" <-- "1" `MemberModel` : Visibility
`ParameterModel` "*" <-- "1" `MemberModel` : Parameters
`RelationshipType` "1" <-- "1" `RelationshipModel` : Type
`ClassModifier` "1" <.. "1" `ClassModel` : Modifier
`MemberModifier` "1" <.. "1" `MemberModel` : Modifier
`CardinalityType` "1" <.. "1" `RelationshipModel` : Cardinality
class `CardinalityType`
<<enumeration>> `CardinalityType`
`CardinalityType`: ManyToMany
`CardinalityType`: ManyToOne
`CardinalityType`: OneToMany
`CardinalityType`: OneToOne
class `ClassModel`
`ClassModel` : +IEnumerable<MemberModel> Members
`ClassModel` : +ClassModifier? Modifier
`ClassModel` : +string Name
`ClassModel` : +string Notes
`ClassModel` : +IEnumerable<string> Values
`ClassModel` : +GetType() Type
class `ClassModifier`
<<enumeration>> `ClassModifier`
`ClassModifier`: Abstract
`ClassModifier`: Interface
`ClassModifier`: Struct
class `MemberModel`
`MemberModel` : +MemberModifier? Modifier
`MemberModel` : +string Name
`MemberModel` : +IEnumerable<ParameterModel> Parameters
`MemberModel` : +string TypeName
`MemberModel` : +MemberVisibility Visibility
`MemberModel` : +GetType() Type
class `MemberModifier`
<<enumeration>> `MemberModifier`
`MemberModifier`: Abstract
`MemberModifier`: Static
class `MemberVisibility`
<<enumeration>> `MemberVisibility`
`MemberVisibility`: Internal
`MemberVisibility`: Private
`MemberVisibility`: Protected
`MemberVisibility`: Public
class `ParameterModel`
`ParameterModel` : +string Name
`ParameterModel` : +string TypeName
`ParameterModel` : +GetType() Type
class `RelationshipModel`
`RelationshipModel` : +CardinalityType? Cardinality
`RelationshipModel` : +string FromType
`RelationshipModel` : +string Label
`RelationshipModel` : +string ToType
`RelationshipModel` : +RelationshipType Type
`RelationshipModel` : +GetType() Type
class `RelationshipType`
<<enumeration>> `RelationshipType`
`RelationshipType`: Aggregation
`RelationshipType`: Association
`RelationshipType`: Composition
`RelationshipType`: Dependency
`RelationshipType`: Inheritence
`RelationshipType`: LinkDashed
`RelationshipType`: LinkSolid
`RelationshipType`: Realization