動態

詳情 返回 返回

實現C#泛型四則運算等特化操作 - 動態 詳情

有些情況下我們會對字段做泛型封裝,使其支持OnChange、IsDirty等統一的功能擴展,例如:

IObservable<float> hitPoint;

 

而有些字段有掛載修改器的需求,修改器若使用lambda則對序列化不友好,因此考慮自行封裝四則運算供修改器

給原始數值進行修改,但C#早期沒有四則運算的接口(Interface)。網上的dynamic動態類型做法對多平台也不太好。

(注:使用擴展方法實現的特化,和這類泛型內特化不太一樣)

 

不轉弱類型的情況下,仍考慮通過接口解決,代碼如下:

public interface IArithmeticOperator<T>
{
    public T Add(T x, T y);
    public T Sub(T x, T y);
    public T Mul(T x, T y);
    public T Div(T x, T y);
}

public static class ArithmeticOperator<T>
{
    public static IArithmeticOperator<T> Instance;

    static ArithmeticOperator()
    {
        var type = typeof(T);

        if (type == typeof(int))
            Instance = (IArithmeticOperator<T>)(object)new IntAritOp();
        else if (type == typeof(float))
            Instance = (IArithmeticOperator<T>)(object)new FloatAritOp();
    }
}

public class IntAritOp : IArithmeticOperator<int>
{
    public int Add(int x, int y) => x + y;
    public int Div(int x, int y) => x / y;
    public int Mul(int x, int y) => x * y;
    public int Sub(int x, int y) => x - y;
}

public class FloatAritOp : IArithmeticOperator<float>
{
    public float Add(float x, float y) => x + y;
    public float Div(float x, float y) => x / y;
    public float Mul(float x, float y) => x * y;
    public float Sub(float x, float y) => x - y;
}

public class AttributeModifier<T>
{
    private T _delta;

    public AttributeModifier(T delta) { this._delta = delta; }

    public T Add(T current) => ArithmeticOperator<T>.Instance.Add(current, _delta);
    public T Sub(T current) => ArithmeticOperator<T>.Instance.Sub(current, _delta);
    public T Mul(T current) => ArithmeticOperator<T>.Instance.Mul(current, _delta);
    public T Div(T current) => ArithmeticOperator<T>.Instance.Div(current, _delta);
}

public class Attribute<T>
{
    private T _Value;
    private AttributeModifier<T> _Modifier;


    public Attribute(T value, AttributeModifier<T> modifier)
    {
        _Value = value;
        _Modifier = modifier;
    }

    public T GetValue()
    {
        // 假設都是乘操作,省略邏輯
        return _Modifier.Mul(_Value);
    }
}

public class Test01 : MonoBehaviour
{
    void Start()
    {
        var hp = new Attribute<int>(100, new AttributeModifier<int>(10));
        Debug.Log(hp.GetValue());//1000
        var stamina = new Attribute<float>(25.5f, new AttributeModifier<float>(2f));
        Debug.Log(stamina.GetValue());//51
    }
}

 

 

而如果需要擴展,如屬性修改器需要直接在泛型類的基礎上支持序列化接口,可以這麼寫:

#region BinarySerializeOperator
public interface IBinarySerializeOperator<T>
{
    public void Serialize(BinaryWriter writer, T inValue);
    public T Deserialize(BinaryReader reader);
}

public static class BinarySerializeOperator<T>
{
    public static IBinarySerializeOperator<T> Instance;

    static BinarySerializeOperator()
    {
        var type = typeof(T);

        if (type == typeof(int))
            Instance = (IBinarySerializeOperator<T>)(object)new IntBinSeriOp();
        else if (type == typeof(float))
            Instance = (IBinarySerializeOperator<T>)(object)new FloatBinSeriOp();
    }
}

public class IntBinSeriOp : IBinarySerializeOperator<int>
{
    public int Deserialize(BinaryReader reader)
    {
        return reader.ReadInt32();
    }

    public void Serialize(BinaryWriter writer, int inValue)
    {
        writer.Write(inValue);
    }
}

public class FloatBinSeriOp : IBinarySerializeOperator<float>
{
    public float Deserialize(BinaryReader reader)
    {
        return reader.ReadSingle();
    }

    public void Serialize(BinaryWriter writer, float inValue)
    {
        writer.Write(inValue);
    }
}
#endregion


public class AttributeModifier<T>
{
    private T _delta;

    public AttributeModifier(T delta) { this._delta = delta; }

    public T Add(T current) => ArithmeticOperator<T>.Instance.Add(current, _delta);
    public T Sub(T current) => ArithmeticOperator<T>.Instance.Sub(current, _delta);
    public T Mul(T current) => ArithmeticOperator<T>.Instance.Mul(current, _delta);
    public T Div(T current) => ArithmeticOperator<T>.Instance.Div(current, _delta);
    public void Serialize(BinaryWriter writer) => BinarySerializeOperator<T>.Instance.Serialize(writer, _delta);
    public void Deserialize(BinaryReader reader) => _delta = BinarySerializeOperator<T>.Instance.Deserialize(reader);
}

 

Add a new 評論

Some HTML is okay.