C#と諸々

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

--/--/-- --:--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
タグ:
トラックバック(-) | コメント(-) | このエントリーを含むはてなブックマーク
2011/01/20 17:36
新規作成時にプロジェクトを保存しないように設定しているのに、普通の .NET Framework 4.0 に変更するためにわざわざプロジェクト保存する必要があって大変うざいです。

そういう時は、プロジェクトのテンプレートを書き換えればおk。
プロジェクトのテンプレートは下記のフォルダの中にあります。

%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplatesCache\CSharp\Windows\1041
例えばコンソールアプリケーションのテンプレートは、下記のファイルになります。

ConsoleApplication.zip\consoleapplication.csproj
こいつを開いて下記の記述を削除すれば、デフォルトでは Client Profile が使用されなくなります。

$if$ ($targetframeworkversion$ >= 4.0)
  <TargetFrameworkProfile>Client</TargetFrameworkProfile>
$endif$


2010/12/28 19:27
プロジェクトのプロパティの [ビルド イベント] - [ビルド前に実行するコマンド ライン] に下記を設定すればOK。 (ファイル名が XMLSchema1.xsd の場合)
outputdir の値の最後にスペースを入れているのがミソ。

"%ProgramFiles%\Microsoft SDKs\Windows\v7.0A\bin\xsd.exe" /classes /language:CS /outputdir:"$(ProjectDir) " "$(ProjectDir)XMLSchema1.xsd"



うーん、昔同じような記事書いた気がしたんだけどなぁ。。。

[関連情報]
XML スキーマ定義ツール (Xsd.exe)



2010/10/26 20:58

.NET クラスライブラリ探訪-038 (System.Tuple)(タプル, 組オブジェクト, 4.0から追加されたクラス) - いろいろ備忘録日記

個人的には以前 今更 Func デリゲートや Action デリゲートについて一言 に書いた理屈と同様に、Tuple も無闇には使わずクラス内部のみといった限定的な利用に留めておくのが良いと考えていますが、Tuple の活用シーンは結構あるのではないかと思います。

Tuple は配列と少し似ていますが、次のような違いがあります。
  • 長さ毎に型が用意されている
  • 各要素は厳密に型付けされる
  • 各要素は読み取り専用
  • Tuple の Equals メソッドは各要素の等値性を比較する
  • Tuple の GetHashCode メソッドは各要素を元にハッシュコードを導出する
特に、下2つが中々に利用価値を高めていると思います。
Tuple は配列やコレクションと違って、同一性ではなく等値性で区別されます。これにより、Tuple を Dictionary の複合キーとして使用することができます。

private Dictionary<Tuple<int, int>, string> _dict;

public string GetValue(int key1, int key2)
{
    return this._dict[Tuple.Create(key1, key2)];
}


また、自作クラス/構造体の Equals メソッド及び GetHashCode メソッドをオーバーライドする時、全てのフィールドをセットした Tuple に処理を委譲することで実装を容易にすることができます。

public sealed class Class1
{
    public Class1(int arg1, string arg2)
    {
        this._field1 = arg1;
        this._field2 = arg2;
    }

    private readonly int _field1;
    private readonly string _field2;

    public override bool Equals(object other)
    {
        var otherAsClass1 = other as Class1;
        if (otherAsClass1 == null)
        {
            return false;
        }

        var thisFieldTuple = this.CreateFieldTuple();
        var otherFieldTuple = otherAsClass1.CreateFieldTuple();

        return thisFieldTuple.Equals(otherFieldTuple);
    }

    public override int GetHashCode()
    {
        var fieldTuple = this.CreateFieldTuple();
        return fieldTuple.GetHashCode();
    }

    private Tuple<int, string> CreateFieldTuple()
    {
        return Tuple.Create(this._field1, this._field2);
    }
}


ということで、Tuple は使い方次第でかなり重宝するかもしれません。
タグ: .NET C#
2010/08/04 21:00
次のような 2 つのクラスがあったとします。

class A
{
}

class B : A
{
}

これらのクラスそれぞれに対し、暗黙的に型変換可能なクラス、A1 クラスと B1 クラスを用意するとします。

class A1
{
    public A1(A source)
    {
        this._source = source;
    }

    private readonly A _source;

    public static implicit operator A(A1 target)
    {
        return target._source;
    }

    public static implicit operator A1(A target)
    {
        return new A1(target);
    }
}

class B1
{
    public B1(B source)
    {
        this._source = source;
    }

    private readonly B _source;

    public static implicit operator B(B1 target)
    {
        return target._source;
    }

    public static implicit operator B1(B target)
    {
        return new B1(target);
    }
}

A1 と B1 は継承関係にありませんが、A と B は継承関係にあります。
そこで、次のように B1 のインスタンスを A1 に型変換できるようにしたいとします。ただし、A1 と B1 はお互いの存在を直接知らないものとします。更に、A1 は A の派生クラスの存在を直接知らないものとします。

B1 b = new B();
A1 a = b;

A1 と B1 はお互いの存在を直接知らないので、まずは間接的に知ることができるよう、A1 と B1 が共通で実装するインターフェイスを用意します。

interface ITypeDef<out T>
{
    T Source
    {
        get;
    }
}

このインターフェイスを実装したコードは次のようになります。

class A1 : ITypeDef<A>
{
    public A1(A source)
    {
        this._source = source;
    }

    protected readonly A _source;

    public static implicit operator A(A1 target)
    {
        return target._source;
    }

    public static implicit operator A1(A target)
    {
        return new A1(target);
    }

    A ITypeDef<A>.Source
    {
        get
        {
            return this._source;
        }
    }
}

class B1 : ITypeDef<B>
{
    public B1(B source)
    {
        this._source = source;
    }

    protected readonly B _source;

    public static implicit operator B(B1 target)
    {
        return target._source;
    }

    public static implicit operator B1(B target)
    {
        return new B1(target);
    }

    B ITypeDef<B>.Source
    {
        get
        {
            return this._source;
        }
    }
}

ITypeDef<T> の型パラメータ T は共変ですので、ITypeDef<B> を ITypeDef<A> に型変換することが可能です。ということは、A1 が ITypeDef<A> からの変換をサポートすれば、ITypeDef<B> を実装する B1 からの変換ができるようになるはずです。

class A1 : ITypeDef<A>
{
    public A1(A source)
    {
        this._source = source;
    }

    protected readonly A _source;

    public static implicit operator A(A1 target)
    {
        return target._source;
    }

    public static implicit operator A1(A target)
    {
        return new A1(target);
    }

    public static implicit operator A1(ITypeDef<A> target)
    {
        return new A1(target.Source);
    }

    A ITypeDef<A>.Source
    {
        get
        {
            return this._source;
        }
    }
}

class B1 : ITypeDef<B>
{
    public B1(B source)
    {
        this._source = source;
    }

    protected readonly B _source;

    public static implicit operator B(B1 target)
    {
        return target._source;
    }

    public static implicit operator B1(B target)
    {
        return new B1(target);
    }

    public static implicit operator B1(ITypeDef<B> target)
    {
        return new B1(target.Source);
    }

    B ITypeDef<B>.Source
    {
        get
        {
            return this._source;
        }
    }
}

残念ながら、このコードはコンパイルが通りません。なぜか C# ではインターフェイスからの変換演算子の定義が禁止されているからです。


さて、今回の目的は恐らく正攻法では実現できません。
ということで、これから非実用的な実現方法を紹介します。

先にも記述しました通り、変換演算子で変換元または変換先をインターフェイスにすることはできません。
そこでジェネリックの型パラメータを利用します。ジェネリックの型パラメータは変換元や変換先に指定することができます。そして、型引数としてインターフェイスを指定することで、間接的に変換元または変換先をインターフェイスにすることができます。
例えば、次のコードでは IEnumerable<int> から Class1<IEnumerable<int>> への変換が実現されます。

using System.Collections.Generic;

class Class1<T>
{
    public Class1(T source)
    {
        this._source = source;
    }

    private readonly T _source;

    public static implicit operator Class1<T>(T target)
    {
        return new Class1<T>(target);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Class1<IEnumerable<int>> c = new List<int>();
    }
}

Class1<T> の型パラメータに IEnumerable<int> と指定していますので、変換演算子は実質次のような形と同等になります。

    public static implicit operator Class1<IEnumerable<int>>(IEnumerable<int> target)
    {
        return new Class1<IEnumerable<int>>(target);
    }

では、話を元に戻して ITypeDef<A> から A1 への変換を実現してみます。
A1 はあくまでも非ジェネリッククラスのままにしたいので、先ほどの Class1<T> よりも更に複雑になります。
A1<T> クラスを用意して、これを A1 が継承するようにします。
A1<T> は A1 のためだけに存在しますので、A1 の定義以外のコードからは直接使用しないようにします。

abstract class A1<T>
    where T : ITypeDef<A>
{
    public static implicit operator A1<T>(T target)
    {
        return (A1<T>)(object)new A1(target.Source);
    }
}

class A1 : A1<ITypeDef<A>>, ITypeDef<A>
{
    public A1(A source)
    {
        this._source = source;
    }

    protected readonly A _source;

    public static implicit operator A(A1 target)
    {
        return target._source;
    }

    public static implicit operator A1(A target)
    {
        return new A1(target);
    }

    A ITypeDef<A>.Source
    {
        get
        {
            return this._source;
        }
    }
}

B1 についても同じようにしておきます。

abstract class B1<T>
    where T : ITypeDef<B>
{
    public static implicit operator B1<T>(T target)
    {
        return (B1<T>)(object)new B1(target.Source);
    }
}

class B1 : B1<ITypeDef<B>>, ITypeDef<B>
{
    public B1(B source)
    {
        this._source = source;
    }

    protected readonly B _source;

    public static implicit operator B(B1 target)
    {
        return target._source;
    }

    public static implicit operator B1(B target)
    {
        return new B1(target);
    }

    B ITypeDef<B>.Source
    {
        get
        {
            return this._source;
        }
    }
}

ところで、A1<T> に定義されている変換演算子は、あくまでも A1 ではなく A1<T> への変換演算子になっています。
つまり、B1 から A1 に変換する際の内部的な流れとしては B1 → A1<T> → A1 という二段階の流れになります。
A1<T> から A1 への変換はダウンキャストとなるため明示的な変換が必要になります。
というわけで、B1 から A1 への変換は暗黙的にはできません。次のように明示的な変換となります。

B1 b = new B();
A1 a = (A1)b;

以上で当初の目的は一応達成できました。
仕組みが複雑なので実用度は低いですね。


2010/07/25 17:08
GC.AddMemoryPressureGC.RemoveMemoryPressure には信頼性のコントラクト (ReliabilityContractAttribute) がない。
ということは、これらは CER 内に含められないし、呼び出し元は Cer.None になってしまう、ということだろーか…?
本来、GC.AddMemoryPressure には Cer.MayFail か Cer.Success が、GC.RemoveMemoryPressure には Cer.Success がマークされてるべきじゃないの??
2010/07/20 01:52

null許容型は参照型と値型のどちらになるの?

C# だとローカル変数への代入は値渡ししかできません。
参照渡しで代入を行うようなコードを C# っぽく書いてみます。

Sample.cs
class Program
{
    static void Main()
    {
        int v0 = 0;
        int& v1 = v0;

        v0 = 5;
        System.Console.WriteLine(v0);
        System.Console.WriteLine(v1);
    }
}


このコードが動作するとすれば、v1 への代入が参照渡しになるので v1 からも 5 が取得されるはずですが、当然ながらこのコードはそもそもコンパイルできません。

しかし、IL ならばローカル変数への参照渡しができます。
先ほどのコードと同等のコードを IL で書くと次のようになります。

Sample.il
.assembly extern mscorlib { }
.assembly sample { }

.class private abstract auto ansi sealed beforefieldinit Program
    extends [mscorlib]System.Object
{
    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .locals init
        (
            [0] valuetype [mscorlib]System.Int32 v0,
            [1] valuetype [mscorlib]System.Int32& v1
        )

        // v0 = 0;
        ldc.i4.0
        stloc.0

        // v1 = v0;
        ldloca.s v0
        stloc.1

        // v0 = 5;
        ldc.i4.5
        stloc.0

        // Console.WriteLine(v0);
        ldloc.0
        call void [mscorlib]System.Console::WriteLine(int32)

        // Console.WriteLine(v2);
        ldloc.1
        ldind.i4
        call void [mscorlib]System.Console::WriteLine(int32)

        ret
    }
}


このコードを次のコマンドで exe ファイルとしてアセンブルします。

ilasm Sample.il


これを実行すると、v0 も v1 も 5 を返すことが確認できます。
つまり、v1 への参照渡しによる代入が可能であることが確認できます。



…まぁ、だからどうというわけでもないんですが。
IL で可能なので、C++/CLI でもできるかもしれませんね。

タグ: .NET C# CLR
2010/07/15 23:13
適当に書いたので注意

using System;
using System.Dynamic;
using System.Reflection;

namespace MoroMoro.Dynamic
{
    public sealed class MemberAdapter : DynamicObject
    {
        private static BindingFlags GetBindingFlags(bool ignoreCase)
        {
            var baseFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
            return (ignoreCase ? (baseFlags | BindingFlags.IgnoreCase) : baseFlags);
        }

        public MemberAdapter(object target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            this._target = target;
        }

        private readonly object _target;

        private Type TargetType
        {
            get
            {
                return this._target.GetType();
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            var flags = GetBindingFlags(binder.IgnoreCase);
            var field = TargetType.GetField(binder.Name, flags);
            var property = TargetType.GetProperty(binder.Name, flags);

            if (field != null)
            {
                result = field.GetValue(this._target);
                return true;
            }
            else if ((property != null) && (property.CanRead))
            {
                result = property.GetValue(this._target, null);
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            var flags = GetBindingFlags(binder.IgnoreCase);
            var field = TargetType.GetField(binder.Name, flags);
            var property = TargetType.GetProperty(binder.Name, flags);

            if (field != null)
            {
                field.SetValue(this._target, value);
                return true;
            }
            else if ((property != null) && (property.CanRead))
            {
                property.SetValue(this._target, value, null);
                return true;
            }
            else
            {
                return false;
            }
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            var flags = GetBindingFlags(binder.IgnoreCase);
            var filter = (MemberFilter)((member, c) =>
            {
                var memberAsMethod = member as MethodInfo;
                if (memberAsMethod == null)
                {
                    return false;
                }
                if (!string.Equals(memberAsMethod.Name, binder.Name, (binder.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)))
                {
                    return false;
                }
                var parameters = memberAsMethod.GetParameters();
                if (args.Length != parameters.Length)
                {
                    return false;
                }
                for (var i = 0; i < parameters.Length; i++)
                {
                    var parameter = parameters[i];
                    var arg = args[i];
                    if (arg == null)
                    {
                        continue;
                    }
                    if (parameter.ParameterType.IsAssignableFrom(arg.GetType()))
                    {
                        continue;
                    }
                    return false;
                }
                return true;
            });
            var methods = TargetType.FindMembers(MemberTypes.Method, flags, filter, null);
            if ((methods == null) || (methods.Length == 0))
            {
                result = null;
                return false;
            }

            var method = (MethodInfo)methods[0];
            result = method.Invoke(this._target, args);
            return true;
        }
    }
}



サンプル
class Program
{
    class Sample
    {
        public Sample()
        {
            this._i = 0;
        }

        private readonly int _i;

        private void Method1()
        {
            Console.WriteLine(_i);
        }
    }

    static void Main()
    {
        var s = new Sample();
        dynamic m = new MemberAdapter(s);
        m._i++;
        m.Method1();

        Console.ReadKey();
    }
}



2010/07/09 21:23
今更ながら式ツリーに入門。
事実上、.NET 4.0 からは構文ツリーに進化したらしい。

例えば、こんな感じのプログラムを式ツリーで構築したいとする。

for (int i = 1; i <= 10; i++)
{
    Console.WriteLine(i);
}



式ツリーでループを組むことはできるが for 文を直接組むことはできないので、こんな感じに変形する。

int i = 1;
while (true)
{
    if (i <= 10)
    {
        Console.WriteLine(i);
    }
    else
    {
        break;
    }
    i++;
}



これを式ツリーで組むとこんな感じになる。

var breakLabel = Expression.Label();
var iParameter = Expression.Variable(typeof(int), "i");
var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(int) });

var lambda = Expression.Lambda
(
    Expression.Block
    (
        new[]
        {
            iParameter
        },
        Expression.Assign(iParameter, Expression.Constant(1)),
        Expression.Loop
        (
            Expression.Block
            (
                Expression.IfThenElse
                (
                    Expression.LessThanOrEqual(iParameter, Expression.Constant(10)),
                    Expression.Call(writeLineMethod, iParameter),
                    Expression.Break(breakLabel)
                ),
                Expression.PostIncrementAssign(iParameter)
            ),
            breakLabel
        )
    )
);

var @delegate = lambda.Compile();
@delegate.DynamicInvoke();



式ツリーを Compile すると DynamicMethod が内部で作られるわけだけど、式ツリーを使わず自分で直接 DynamicMethod を構築するとなると IL を組み立てていくことになるので一苦労。IL だから for 文どころかループもないので、ラベルと goto で…。
ちなみに、CompileToMethod を使用すれば動的クラスの静的メソッドも構築できる。残念ながら動的クラスのインスタンスメソッドを構築することはできない。

最後に、AST (IronPython 同梱の Microsoft.Dynamic.dll に含まれている) を使用すると for 文が簡単に作れるので結構すっきりする。

var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(int) });

var builder = Utils.Lambda(typeof(void), string.Empty);
var iParameter = builder.Variable(typeof(int), "i");
builder.Body = Expression.Block
(
    Expression.Assign(iParameter, Expression.Constant(1)),
    Utils.Loop
    (
        Expression.LessThanOrEqual(iParameter, Expression.Constant(10)),
        Expression.PostIncrementAssign(iParameter),
        Expression.Call(writeLineMethod, iParameter),
        null
    )
);

var lambda = builder.MakeLambda();
var @delegate = lambda.Compile();
@delegate.DynamicInvoke();





2010/06/30 23:44

タグ: .NET C# Silverlight
2010/06/25 01:08

ガード句っぽい選択

あー本題からそれてるような気もしますが。
あと型名勝手に変えちゃいましたが。

class Generation
{
    public static readonly Generation Over60  = new Generation(60, null);
    public static readonly Generation Over50  = new Generation(50, 59);
    public static readonly Generation Over40  = new Generation(40, 49);
    public static readonly Generation Over30  = new Generation(30, 39);
    public static readonly Generation Over20  = new Generation(20, 29);
    public static readonly Generation Under20 = new Generation(null, 19);

    public static Generation GetGeneration(int age)
    {
        return
            new[]
            {
                Over60,
                Over50,
                Over40,
                Over30,
                Over20,
                Under20,
            }
            .Single(item => item.IsIncludeing(age));
    }


    private Generation(int? lowerLimit, int? upperLimit)
    {
        LowerLimit = lowerLimit;
        UpperLimit = upperLimit;
    }

    public readonly int? LowerLimit;
    public readonly int? UpperLimit;

    public bool IsIncludeing(int age)
    {
        bool isWithinLowerLimit = LowerLimit.HasValue ? (LowerLimit <= age) : true;
        bool isWithinUpperLimit = UpperLimit.HasValue ? (age <= UpperLimit) : true;
        return isWithinLowerLimit && isWithinUpperLimit;
    }
}


元ネタにあるような特定の使い方だけしかしない内は、
こんなクラス化なんてやりすぎですが、
色々な使い方が出てきたときにはこういう方向に進んでいくことかと思います。

ついでに、Static フィールド の種類を増やす時に変更箇所が一箇所で済むよう
リフレクションとカスタム属性を導入してみます。

class Generation
{
    class ItemAttribute : Attribute { }

    [Item]public static readonly Generation Over60  = new Generation(60, null);
    [Item]public static readonly Generation Over50  = new Generation(50, 59);
    [Item]public static readonly Generation Over40  = new Generation(40, 49);
    [Item]public static readonly Generation Over30  = new Generation(30, 39);
    [Item]public static readonly Generation Over20  = new Generation(20, 29);
    [Item]public static readonly Generation Under20 = new Generation(null, 19);
    private static ReadOnlyCollection<Generation> _items = CreateItems();

    private static ReadOnlyCollection<Generation> CreateItems()
    {
        var query =
            from field in typeof(Generation).GetFields(BindingFlags.Static | BindingFlags.Public)
            where (field.IsDefined(typeof(ItemAttribute), false))
            select (field.GetValue(null) as Generation);

        return new ReadOnlyCollection<Generation>(query.ToList());
    }

    public static Generation GetGeneration(int age)
    {
        return _items.Single(item => item.IsIncludeing(age));
    }


    private Generation(int? lowerLimit, int? upperLimit)
    {
        LowerLimit = lowerLimit;
        UpperLimit = upperLimit;
    }

    public readonly int? LowerLimit;
    public readonly int? UpperLimit;

    public bool IsIncludeing(int age)
    {
        bool isWithinLowerLimit = LowerLimit.HasValue ? (LowerLimit <= age) : true;
        bool isWithinUpperLimit = UpperLimit.HasValue ? (age <= UpperLimit) : true;
        return isWithinLowerLimit && isWithinUpperLimit;
    }
}


若干やりすぎた感があります。


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。