This package provides UnionAttribute, which can be used to generate a container struct that can hold one of several
specified struct types. The generated struct can also implement specified in ExposeAttribute interfaces.
Key Features:
- UnionAttribute: Specifies that the container struct can hold only one of the specified struct types at a time.
- ExposeAttribute: Specifies that the container struct should implement the specified interfaces, delegating the implementation to the currently held struct.
Define the container struct using the UnionAttribute and ExposeAttribute attributes:
usingAppegy.Union.Cells.Variants;namespaceAppegy.Union.Cells{[Union(typeof(VoidCell),typeof(EmptyCell),typeof(RegularCell))][Expose(typeof(IPuzzleCell),typeof(IMatchableCell),typeof(IMovableCell))]publicpartialstructPuzzleCell{}}Define the structs and the interface that the container struct will implement:
namespaceAppegy.Union.Cells{publicinterfaceIPuzzleCell{publicshortId{get;}}publicinterfaceIMovableCell{publicboolMovable{get;}}publicinterfaceIMatchableCell{publicboolMatchable{get;}}}namespaceAppegy.Union.Cells.Variants{publicstructVoidCell:IPuzzleCell,IMovableCell,IMatchableCell{publicshortId=>-2;publicboolMovable=>false;publicboolMatchable=>false;}publicstructEmptyCell:IPuzzleCell,IMovableCell,IMatchableCell{publicshortId=>-1;publicboolMovable=>false;publicboolMatchable=>false;}publicstructRegularCell:IPuzzleCell,IMovableCell,IMatchableCell{publicshortId{get;set;}publicboolMovable=>true;publicboolMatchable=>true;publicRegularCell(shortid){Id=id;}}}That is it. Generator will generate all necessary code.
// Create an array of PuzzleCellPuzzleCell[]puzzleCells=newPuzzleCell[3];// Add different cell types to the arraypuzzleCells[0]=newVoidCell();puzzleCells[1]=newEmptyCell();puzzleCells[2]=newRegularCell(42);// Print information about the cellsforeach(varcellinpuzzleCells){Debug.Log($"Type: {cell.Type}, Id: {cell.Id}, Movable: {cell.Movable}, Matchable: {cell.Matchable}");}foreach(varcellinpuzzleCells){switch(cell.Type){casePuzzleCell.Kind.VoidCell:Debug.Log("This is a VoidCell");break;casePuzzleCell.Kind.EmptyCell:Debug.Log("This is an EmptyCell");break;casePuzzleCell.Kind.RegularCell:Debug.Log("This is a RegularCell with Id: "+cell.Id);break;default:thrownewArgumentOutOfRangeException();}}// Implicit conversion from VoidCell to PuzzleCellPuzzleCellvoidCell=newVoidCell();// Implicit conversion from PuzzleCell back to VoidCellVoidCellextractedVoidCell=voidCell;// Create a RegularCellPuzzleCellregularCell=newRegularCell(42);// Use the IPuzzleCell interfaceIPuzzleCellpuzzleCellInterface=regularCell;Debug.Log($"IPuzzleCell Id: {puzzleCellInterface.Id}");// Use the IMovableCell interfaceIMovableCellmovableCellInterface=regularCell;Debug.Log($"IMovableCell Movable: {movableCellInterface.Movable}");// Use the IMatchableCell interfaceIMatchableCellmatchableCellInterface=regularCell;Debug.Log($"IMatchableCell Matchable: {matchableCellInterface.Matchable}");Debug.Log($"Extracted VoidCell Id: {extractedVoidCell.Id}");// <auto-generated/>usingSystem;usingSystem.Runtime.InteropServices;usingAppegy.Union.Cells.Variants;namespaceAppegy.Union.Cells{[StructLayout(LayoutKind.Explicit,Pack=1)]partialstructPuzzleCell:IEquatable<PuzzleCell>,IEquatable<VoidCell>,IEquatable<EmptyCell>,IEquatable<RegularCell>{[Serializable]publicenumKind:byte{VoidCell,EmptyCell,RegularCell,}[FieldOffset(0)]privateKind_type;[FieldOffset(1)]privateVoidCell_voidCell;[FieldOffset(1)]privateEmptyCell_emptyCell;[FieldOffset(1)]privateRegularCell_regularCell;publicKindType=>_type;publicVoidCellVoidCell{get=>Type!=Kind.VoidCell?thrownewException($"Can't get VoidCell because current type is '{Type}'."):_voidCell;set{_type=Kind.VoidCell;_voidCell=value;}}publicEmptyCellEmptyCell{get=>Type!=Kind.EmptyCell?thrownewException($"Can't get EmptyCell because current type is '{Type}'."):_emptyCell;set{_type=Kind.EmptyCell;_emptyCell=value;}}publicRegularCellRegularCell{get=>Type!=Kind.RegularCell?thrownewException($"Can't get RegularCell because current type is '{Type}'."):_regularCell;set{_type=Kind.RegularCell;_regularCell=value;}}publicPuzzleCell(VoidCellvalue){_type=Kind.VoidCell;_emptyCell=default;_regularCell=default;_voidCell=value;}publicPuzzleCell(EmptyCellvalue){_type=Kind.EmptyCell;_voidCell=default;_regularCell=default;_emptyCell=value;}publicPuzzleCell(RegularCellvalue){_type=Kind.RegularCell;_voidCell=default;_emptyCell=default;_regularCell=value;}publicoverridestringToString()=>_typeswitch{Kind.VoidCell=>_voidCell.ToString(),Kind.EmptyCell=>_emptyCell.ToString(),Kind.RegularCell=>_regularCell.ToString(),
_ =>thrownewInvalidOperationException($"Unknown type of union: {_type}")};publicoverrideintGetHashCode()=>_typeswitch{Kind.VoidCell=>_voidCell.GetHashCode(),Kind.EmptyCell=>_emptyCell.GetHashCode(),Kind.RegularCell=>_regularCell.GetHashCode(),
_ =>thrownewInvalidOperationException($"Unknown type of union: {_type}")};publicoverrideboolEquals(objectboxed)=>boxedswitch{PuzzleCellother=>Equals(other),VoidCellother=>Equals(other),EmptyCellother=>Equals(other),RegularCellother=>Equals(other),
_ =>thrownewInvalidOperationException($"Unknown type of union: {_type}")};publicboolEquals(PuzzleCellother)=>_type==other.Type&&_typeswitch{Kind.VoidCell=>_voidCell.Equals(other.VoidCell),Kind.EmptyCell=>_emptyCell.Equals(other.EmptyCell),Kind.RegularCell=>_regularCell.Equals(other.RegularCell),
_ =>thrownewInvalidOperationException($"Unknown type of union: {_type}")};publicboolEquals(VoidCellother)=>_type==Kind.VoidCell&&_voidCell.Equals(other);publicboolEquals(EmptyCellother)=>_type==Kind.EmptyCell&&_emptyCell.Equals(other);publicboolEquals(RegularCellother)=>_type==Kind.RegularCell&&_regularCell.Equals(other);publicstaticimplicitoperatorVoidCell(PuzzleCellother)=>other.VoidCell;publicstaticimplicitoperatorPuzzleCell(VoidCellother)=>newPuzzleCell(other);publicstaticimplicitoperatorEmptyCell(PuzzleCellother)=>other.EmptyCell;publicstaticimplicitoperatorPuzzleCell(EmptyCellother)=>newPuzzleCell(other);publicstaticimplicitoperatorRegularCell(PuzzleCellother)=>other.RegularCell;publicstaticimplicitoperatorPuzzleCell(RegularCellother)=>newPuzzleCell(other);publicstaticbooloperator==(PuzzleCella,PuzzleCellb)=>a.Equals(b);publicstaticbooloperator!=(PuzzleCella,PuzzleCellb)=>!a.Equals(b);publicstaticbooloperator==(PuzzleCella,VoidCellb)=>a.Equals(b);publicstaticbooloperator!=(PuzzleCella,VoidCellb)=>!a.Equals(b);publicstaticbooloperator==(PuzzleCella,EmptyCellb)=>a.Equals(b);publicstaticbooloperator!=(PuzzleCella,EmptyCellb)=>!a.Equals(b);publicstaticbooloperator==(PuzzleCella,RegularCellb)=>a.Equals(b);publicstaticbooloperator!=(PuzzleCella,RegularCellb)=>!a.Equals(b);}}// <auto-generated/>usingSystem;usingSystem.Runtime.InteropServices;usingAppegy.Union.Cells.Variants;usingAppegy.Union.Cells;namespaceAppegy.Union.Cells{partialstructPuzzleCell:IPuzzleCell,IMatchableCell,IMovableCell{
#region Implement IPuzzleCell
publicshortId{get{switch(_type){caseKind.VoidCell:return_voidCell.Id;caseKind.EmptyCell:return_emptyCell.Id;caseKind.RegularCell:return_regularCell.Id;default:thrownewInvalidOperationException($"Unknown type of union: {_type}");}}}
#endregion Implement IPuzzleCell
#region Implement IMatchableCell
publicboolMatchable{get{switch(_type){caseKind.VoidCell:return_voidCell.Matchable;caseKind.EmptyCell:return_emptyCell.Matchable;caseKind.RegularCell:return_regularCell.Matchable;default:thrownewInvalidOperationException($"Unknown type of union: {_type}");}}}
#endregion Implement IMatchableCell
#region Implement IMovableCell
publicboolMovable{get{switch(_type){caseKind.VoidCell:return_voidCell.Movable;caseKind.EmptyCell:return_emptyCell.Movable;caseKind.RegularCell:return_regularCell.Movable;default:thrownewInvalidOperationException($"Unknown type of union: {_type}");}}}
#endregion Implement IMovableCell
}}