C#と諸々

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

--/--/-- --:--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
タグ:
トラックバック(-) | コメント(-) | このエントリーを含むはてなブックマーク
2011/03/05 23:38
C#と諸々 もし最初から拡張メソッドがあったら

こんな感じ。

class Hoge
{
}

class Fuga : Hoge
{
}

class Piyo : Hoge
{
}

class Program
{
    static void Main(string[] args)
    {
        var hoge1 = new Hoge();
        var hoge2 = new Hoge();
        var fuga1 = new Fuga();
        var fuga2 = new Fuga();
        var piyo  = new Piyo();

        bool b1 = hoge1.Equals(hoge2);      // T = Hoge
        bool b2 = hoge1.Equals(fuga1);      // T = Hoge

        bool b3 = fuga1.Equals(fuga2);      // T = Fuga
        bool b4 = fuga1.Equals(hoge1);      // T = Hoge (!!)

      //bool b5 = fuga1.Equals(piyo);       // Build Error !!
        bool b6 = fuga1.Equals((Hoge)piyo); // T = Hoge
        bool b7 = fuga1.Equals<Hoge>(piyo); // T = Hoge
    }
}


[検証プログラム]
インテリセンスに Object.Equals(object) が出てこないこと、Equals の引数の型が自分自身になることを確認できます。
ビルドが出来るだけで実行は出来ません。

ダウンロードページ


2011/03/05 02:08
Equals メソッドの引数の型は自分自身の型にできたんじゃなかろーか。

public class Object
{
    protected internal virtual bool Equals(object obj)
    {
        ...
    }
}

public static class ObjectExtension
{
    public static bool Equals<T>(this T source, T obj)
    {
        if (source == null)
        {
            // return (obj == null); にするのも面白い
            throw new NullReferenceException();
        }
        return source.Equals((object)obj);
    }
}


あまり深く考えずに言っているので、なんらかの不都合が生じるかもしれないけど。。。
つか、拡張メソッドのサポートを全ての言語に強いることになるからダメかな。
つかつか、やっぱし自分自身の型を示すキーワードが欲しくなる。

2011/02/16 17:25
タグ: .NET ASP.NET SQL_Server
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$


2011/01/11 14:53

コンソール アプリケーションの作り方 ≪ ++C++; // 未確認飛行 C ブログ より

PowerShell って .NET Framework 4 で作ったアセンブリ読み込めないんですよねぇ・・・。アップデートして欲しい・・・


確か CLR のバージョンって指定できたなぁと思い調べてみたらできました。
これで .NET 4.0 の新しいクラスを使用したり、アセンブリを読み込んだりすることができます。

[手順]
PowerShell のインストールフォルダ (%windir%\system32\WindowsPowerShell\v1.0) に次のファイルを作成する。

powershell.exe.config
<?xml version ="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true" >
    <supportedRuntime version="v4.0.30319" />
  </startup>
</configuration>




タグ: .NET PowerShell CLR
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
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。