• Design
  • API Reference
  • Changelog
  • Contribute
Show / Hide Table of Contents
  • Libplanet
    • Address
    • AddressExtension
    • ByteUtil
    • Hashcash
    • Hashcash.Stamp
    • HashDigest<T>
    • HashDigestExtension
    • Nonce
  • Libplanet.Action
    • AccountStateGetter
    • ActionEvaluation
    • ActionTypeAttribute
    • AddressStateMap
    • IAccountStateDelta
    • IAction
    • IActionContext
    • IRandom
    • MissingActionTypeException
    • PolymorphicAction<T>
  • Libplanet.Blockchain
    • BlockChain<T>
    • IncompleteBlockStatesException
    • MineBlockEventArgs<T>
  • Libplanet.Blockchain.Policies
    • BlockPolicy<T>
    • BlockPolicyExtension
    • IBlockPolicy<T>
  • Libplanet.Blocks
    • Block<T>
    • InvalidBlockDifficultyException
    • InvalidBlockException
    • InvalidBlockHashException
    • InvalidBlockIndexException
    • InvalidBlockNonceException
    • InvalidBlockPreviousHashException
    • InvalidBlockTimestampException
  • Libplanet.Crypto
    • InvalidCiphertextException
    • PrivateKey
    • PublicKey
    • SymmetricKey
  • Libplanet.Net
    • ActionExecutionState
    • BlockDownloadState
    • BlockStateDownloadState
    • DifferentAppProtocolVersionException
    • DifferentProtocolVersionEventArgs
    • IceServer
    • IceServerException
    • InvalidMessageException
    • NoSwarmContextException
    • Peer
    • PeerNotFoundException
    • PeerSetDelta
    • PreloadState
    • StateReferenceDownloadState
    • Swarm<T>
    • SwarmException
  • Libplanet.Serialization
    • BencodexFormatter<T>
    • SerializationInfoExtension
  • Libplanet.Store
    • BaseIndex<TKey, TVal>
    • BaseStore
    • BlockSet<T>
    • IStore
    • LiteDBStore
    • NamespaceNotFoundException
    • StoreExtension
    • TransactionSet<T>
  • Libplanet.Tx
    • InvalidTxException
    • InvalidTxIdException
    • InvalidTxNonceException
    • InvalidTxPublicKeyException
    • InvalidTxSignatureException
    • InvalidTxUpdatedAddressesException
    • Transaction<T>
    • TxId
    • UnexpectedlyTerminatedTxRehearsalException

Class PolymorphicAction<T>

A decorator to enable subtype polymorphism for action classes.

By convention, concrete action subclasses are named with verb phrases, e.g., Heal, Sell.

One downside of this compared to the vanilla IAction is the fact that it uses reflection under the hood. This may cause compatibility issues on certain platforms, and is slightly slower.

Inheritance
Object
PolymorphicAction<T>
Implements
IAction
Inherited Members
Object.Equals(Object)
Object.Equals(Object, Object)
Object.GetHashCode()
Object.GetType()
Object.MemberwiseClone()
Object.ReferenceEquals(Object, Object)
Object.ToString()
Namespace: Libplanet.Action
Assembly: Libplanet.dll
Syntax
public sealed class PolymorphicAction<T> : IAction where T : IAction
Type Parameters
Name Description
T

An action base class which implements IAction and has subclasses. Usually an abstract class.

Remarks

Every concrete action subclass of T has to be marked with the ActionTypeAttribute. Even if a superclass is marked with the ActionTypeAttribute its subclass also should be marked with the ActionTypeAttribute if it is concrete.

Examples

The following example shows how polymorphic actions look like (compare this with an IAction example without subtype polymorphism):

using System;
using System.Collections.Immutable;
using Libplanet;
using Libplanet.Action;

// Instead of having multiple in-game actions in a class,
// in this example, we declare one abstract base class
// and its three concrete subclasses.
public abstract class ActionBase : IAction
{
    public ActionBase() { }

    public ActionBase(Address targetAddress)
    {
        TargetAddress = targetAddress;
    }

    public Address TargetAddress { get; private set; }

    // Leaves Execute() abstract so that concrete subclasses
    // implement their own logic.
    public abstract IAccountStateDelta Execute(IActionContext context);

    // Makes Render() no-op by default, but overrideable by subclasses.
    public virtual void Render(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
    }

    // Makes Unrender() no-op by default,
    // but overrideable by subclasses.
    public virtual void Unrender(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
    }

    IImmutableDictionary<string, object> IAction.PlainValue =>
        ImmutableDictionary<string, object>.Empty
            .Add("target_address", TargetAddress);

    void IAction.LoadPlainValue(
        IImmutableDictionary<string, object> plainValue)
    {
        TargetAddress = (Address)plainValue["target_address"];
    }
}

// PolymorphicAction<T> requires concrete action classes marked with
// ActionTypeAttribute.
// There is only one required parameter to ActionTypeAttribute,
// which takes a unique identifier of the action type.
// This is used for serialization and deserialization under the hood.
[ActionType("create_character")]
public sealed class CreateCharacter : ActionBase
{
    public override IAccountStateDelta Execute(IActionContext context)
    {
        var state = (ImmutableDictionary<string, uint>)
            context.PreviousStates.GetState(TargetAddress);
        if (!TargetAddress.Equals(context.Signer))
            throw new Exception(
                "TargetAddress of CreateCharacter action only can be " +
                "the same address to the Transaction<T>.Signer."
            );
        else if (!(state is null))
            throw new Exception("Character was already created.");
        return context.PreviousStates.SetState(
            TargetAddress,
            ImmutableDictionary<string, uint>.Empty.Add("hp", 20)
        );
    }

    void IAction.Render(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        var c = new Character
        {
            Address = TargetAddress,
            Hp = nextStates.GetState(TargetAddress)["hp"],
        };
        c.Draw();
        break;
    }

    void IAction.Unrender(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        Character c = Character.GetByAddress(TargetAddress);
        c.Hide();
    }
}

[ActionType("attack")]
public sealed class Attack : ActionBase
{
    public override IAccountStateDelta Execute(IActionContext context)
    {
        var state = (ImmutableDictionary<string, uint>)
            context.PreviousStates.GetState(TargetAddress);
        return context.PreviousStates.SetState(
            TargetAddress,
            state.SetItem("hp", Math.Max(state["hp"] - 5, 0))
        );
    }

    void IAction.Render(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        Character c = Character.GetByAddress(TargetAddress);
        c.Hp = nextStates.GetState(TargetAddress)["hp"];
        c.Draw();
    }

    void IAction.Unrender(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        Character c = Character.GetByAddress(TargetAddress);
        c.Hp = context.PreviousStates.GetState(TargetAddress)["hp"];
        c.Draw();
    }
}

[ActionType("heal")]
public sealed class Heal : ActionBase
{
    public override IAccountStateDelta Execute(IActionContext context)
    {
        var state = (ImmutableDictionary<string, uint>)
            context.PreviousStates.GetState(TargetAddress);
        return context.PreviousStates.SetState(
            TargetAddress,
            state.SetItem("hp", Math.Min(state["hp"] + 5, 20))
        );
    }

    void IAction.Render(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        Character c = Character.GetByAddress(TargetAddress);
        c.Hp = nextStates.GetState(TargetAddress)["hp"];
        c.Draw();
    }

    void IAction.Unrender(
        IActionContext context,
        IAccountStateDelta nextStates)
    {
        Character c = Character.GetByAddress(TargetAddress);
        c.Hp = context.PreviousStates.GetState(TargetAddress)["hp"];
        c.Draw();
    }
}

Constructors

| Improve this Doc View Source

PolymorphicAction()

Do not use this constructor. Use PolymorphicAction(T) instead.

Declaration
[Obsolete]
public PolymorphicAction()
| Improve this Doc View Source

PolymorphicAction(T)

Creates a new PolymorphicAction<T> instance wrapping an innerAction.

Declaration
public PolymorphicAction(T innerAction)
Parameters
Type Name Description
T innerAction

An instance of T (or one of its subtypes) to wrap.

Exceptions
Type Condition
MissingActionTypeException

Thrown when the class of the given innerAction is not annotated with ActionTypeAttribute.

Properties

| Improve this Doc View Source

InnerAction

The wrapped action object of T (or one of its subtypes).

Declaration
public T InnerAction { get; }
Property Value
Type Description
T
| Improve this Doc View Source

PlainValue

Declaration
public IImmutableDictionary<string, object> PlainValue { get; }
Property Value
Type Description
IImmutableDictionary<String, Object>

Methods

| Improve this Doc View Source

Execute(IActionContext)

Declaration
public IAccountStateDelta Execute(IActionContext context)
Parameters
Type Name Description
IActionContext context
Returns
Type Description
IAccountStateDelta
| Improve this Doc View Source

LoadPlainValue(IImmutableDictionary<String, Object>)

Declaration
public void LoadPlainValue(IImmutableDictionary<string, object> plainValue)
Parameters
Type Name Description
IImmutableDictionary<String, Object> plainValue
| Improve this Doc View Source

Render(IActionContext, IAccountStateDelta)

Declaration
public void Render(IActionContext context, IAccountStateDelta nextStates)
Parameters
Type Name Description
IActionContext context
IAccountStateDelta nextStates
| Improve this Doc View Source

Unrender(IActionContext, IAccountStateDelta)

Declaration
public void Unrender(IActionContext context, IAccountStateDelta nextStates)
Parameters
Type Name Description
IActionContext context
IAccountStateDelta nextStates

Operators

| Improve this Doc View Source

Implicit(T to PolymorphicAction<T>)

For convenience, an inner action T can be implicitly casted to PolymorphicAction<T>.

Declaration
public static implicit operator PolymorphicAction<T>(T innerAction)
Parameters
Type Name Description
T innerAction

An instance of T (or one of its subtypes) to wrap.

Returns
Type Description
PolymorphicAction<T>

A PolymorphicAction<T> wrapping the given innerAction.

Exceptions
Type Condition
MissingActionTypeException

Thrown when the class of the given innerAction is not annotated with ActionTypeAttribute.

Implements

IAction
  • Improve this Doc
  • View Source
Back to top Copyright © 2019 Planetarium
Generated by DocFX