C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2009/06/15 01:33
bleis-tift さんが前に言ってた、D 言語の強い typedef が C# にも欲しいなぁです。
まぁ無いものはしょうがないってことで、お遊びでこんなクラス作ってみました。

Int32Def(TSelf).cs
using System;
using System.Runtime.Serialization;
using System.Reflection;

public abstract class Int32Def<TSelf>
    where TSelf : Int32Def<TSelf>
{
    private readonly int _value;

    public static implicit operator int(Int32Def<TSelf> value)
    {
        return value._value;
    }

    public static explicit operator Int32Def<TSelf>(int value)
    {
        TSelf obj = (TSelf)FormatterServices.GetUninitializedObject(typeof(TSelf));
        FieldInfo valueField = typeof(Int32Def<TSelf>).GetField("_value", BindingFlags.NonPublic | BindingFlags.Instance);
        valueField.SetValue(obj, value);
        return obj;
    }

    public static TSelf operator +(Int32Def<TSelf> value)
    {
        return (TSelf)(+value._value);
    }

    public static TSelf operator -(Int32Def<TSelf> value)
    {
        return (TSelf)(-value._value);
    }

    public static TSelf operator ~(Int32Def<TSelf> value)
    {
        return (TSelf)(~value._value);
    }

    public static TSelf operator ++(Int32Def<TSelf> value)
    {
        int temp = value._value;
        temp++;
        return (TSelf)(temp);
    }

    public static TSelf operator --(Int32Def<TSelf> value)
    {
        int temp = value._value;
        temp--;
        return (TSelf)(temp);
    }

    public static TSelf operator +(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value + value2._value);
    }

    public static TSelf operator -(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value - value2._value);
    }

    public static TSelf operator *(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value * value2._value);
    }

    public static TSelf operator /(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value / value2._value);
    }

    public static TSelf operator %(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value % value2._value);
    }

    public static TSelf operator &(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value & value2._value);
    }

    public static TSelf operator |(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value | value2._value);
    }

    public static TSelf operator ^(Int32Def<TSelf> value1, Int32Def<TSelf> value2)
    {
        return (TSelf)(value1._value ^ value2._value);
    }

    public static TSelf operator <<(Int32Def<TSelf> value1, int value2)
    {
        return (TSelf)(value1._value << value2);
    }

    public static TSelf operator >>(Int32Def<TSelf> value1, int value2)
    {
        return (TSelf)(value1._value >> value2);
    }
}


Program.cs
using System;

class Hoge : Int32Def<Hoge>
{
}

class Fuga : Int32Def<Fuga>
{
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Test((Hoge)5, (Hoge)10)); //=> 15
        Console.WriteLine(Test((Fuga)5, (Fuga)10)); //=> 50
    }

    static Hoge Test(Hoge a, Hoge b)
    {
        return a + b;
    }

    static Fuga Test(Fuga a, Fuga b)
    {
        return a * b;
    }
}



あくまでもお遊びです。Int32 限定ですし、構造体ではなくクラス (従って null がありえますし現時点では対策してません) です。あと、演算子しか考慮してません。

ちなみに T4 Template 版もあります。まだ詰めが甘いですが。こちらは構造体としてコード生成するので、null を許容しません。あと、Int32 以外のプリミティブ型もたぶん行けます、たぶん。
こっちはもうちょい頑張れば実用的なものにできるかなと思います。

<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#
    string namespaceName = "Samples";
    string newTypeName = "Hoge";
    string sourceTypeName = "int";
   
    string[] unaryOperators = new string[]
    {
        "+",
        "-",
        "~",
        //"!",
    };
   
    string[] destructiveUnaryOperators = new string[]
    {
        "++",
        "--",
    };
   
    string[] binaryOperators = new string[]
    {
        "+",
        "-",
        "*",
        "/",
        "%",
        "&",
        "|",
        "^",
    };
   
    string[] booleanOperators = new string[]
    {
        "true",
        "false"
    };
   
    string[] shiftOperators = new string[]
    {
        "<<",
        ">>"
    };
   
    string[] comparisonOperators = new string[]
    {
        "==",
        "!=",
        "<",
        ">",
        "<=",
        ">="
    };
#>
namespace <#= namespaceName #>
{
    public struct <#= newTypeName #>
    {
        public <#= newTypeName #>(<#= sourceTypeName #> value)
        {
            this._value = value;
        }
       
        private readonly <#= sourceTypeName #> _value;
       
        public static implicit operator <#= sourceTypeName #>(<#= newTypeName #> value)
        {
            return value._value;
        }
       
        public static explicit operator <#= newTypeName #>(<#= sourceTypeName #> value)
        {
            return new <#= newTypeName #>(value);
        }
<#
    foreach (string unaryOperator in unaryOperators)
    {
#>

        public static <#= newTypeName #> operator <#= unaryOperator #>(<#= newTypeName #> value)
        {
            return new <#= newTypeName #>(<#= unaryOperator #>value._value);
        }
<#
    }
#>
<#
    foreach (string destructiveUnaryOperator in destructiveUnaryOperators)
    {
#>

        public static <#= newTypeName #> operator <#= destructiveUnaryOperator #>(<#= newTypeName #> value)
        {
            <#= sourceTypeName #> temp = value._value;
            temp<#= destructiveUnaryOperator #>;
            return new <#= newTypeName #>(temp);
        }
<#
    }
#>
<#
    foreach (string binaryOperator in binaryOperators)
    {
#>

        public static <#= newTypeName #> operator <#= binaryOperator #>(<#= newTypeName #> value1, <#= newTypeName #> value2)
        {
            return new <#= newTypeName #>(value1._value <#= binaryOperator #> value2._value);
        }
<#
    }
#>
<#
    foreach (string shiftOperator in shiftOperators)
    {
#>

        public static <#= newTypeName #> operator <#= shiftOperator #>(<#= newTypeName #> value1, int value2)
        {
            return new <#= newTypeName #>(value1._value <#= shiftOperator #> value2);
        }
<#
    }
#>
<#
/*
    foreach (string booleanOperator in booleanOperators)
    {
#>

        public static bool operator <#= booleanOperator #>(<#= newTypeName #> value)
        {
            throw new System.NotImplementedException();
        }
<#
    }
*/
#>
    }
}


T4 Template はじめて知りました!
これは面白そう・・・

2009.06.16 11:18 URL | bleis-tift #- [ 編集 ]


コード生成が手軽に出来ていいですよ
といっても僕もそれ程活用してるわけじゃないですが^^;

ちなみに、T4 Template については↓の書籍でそれなりに解説されてます。
http://www.amazon.co.jp/dp/4891005742

そういえばこの本も半積読状態…。

2009.06.16 17:18 URL | よこけん #Ay6tTHf6 [ 編集 ]


その本、気になってはいたんですが、いつの間にか忘れてましたw
お金に余裕が出来たら買ってみます!

2009.06.17 15:20 URL | bleis-tift #- [ 編集 ]












トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/269-ced132bc

[C#]C# で強い typedef
C#と諸々 強い typedef が欲しい 弱い typedef (alias) に継承は使えないけど、強い typedef には継承が使えるというか、持ってこいだと言うことに今まで全く気付いていなかった・・・ T4 Template は存在自体知らなかったけど、かなり良さそうなので早速導入することに。

2009.06.16 17:09 | 予定は未定Blog版