2006年08月23日

C#のパーシャルクラスとデザイナが生成したコードについて考えてみる

   このエントリーをはてなブックマークに追加 Clip to Evernote
以前「TableAdapter で Command のタイムアウトを設定するには」で、TableAdapterの数だけ、CommandTimeoutプロパティを書かないといけない。と書いたが、再度、考えてみた。
partila Class MyClass {
...
}

というデザイナーが作成したコードがあった場合、ユーザが記述する、パーシャルクラスのほうで、継承元のクラスを指定することが可能だ。
なので、自分が記述するクラスでは、
partila Class MyClass : BaseClass {
...
}

と書けば、MyClass は、BaseClass から派生させることが可能。

でも、TableAdapterは、System.ComponentModel.Component から派生しているのでだめだ。

委譲も 同様の理由でだめ。
以下のように、各TableAdapterが、TableAdapter という基本クラスから派生していれば、もう少しやりようがあるのにな...
 public partial class TableAdapter : System.ComponentModel.Component { 
protected System.Data.SqlClient.SqlDataAdapter _adapter;
protected System.Data.SqlClient.SqlConnection _connection;
protected System.Data.SqlClient.SqlCommand[] _commandCollection;
protected bool _clearBeforeFill;
....
}

public partial class MyTableAdapter : TableAdapter {
...
}

こうなっていれば、
 public partial class TableAdapter { 
public int CommandTimeout {
get {
return ( this._commandCollection[0].CommandTimeout );
}
set {
for ( int i = 0; i < this.CommandCollection.Length; i++ ) {
if ( ( this.CommandCollection[i] != null ) ) {
( (System.Data.SqlClient.SqlCommand)
( this.CommandCollection[i] ) ).CommandTimeout = value;
}
}
}
}
...
}

と書ける。これで、すべてのTableAdapterに有効なプロパティを書けるので、拡張が簡単だ。
ただ、むやみやたらに、TableAdapter に拡張機能を入れられると、TableAdapterが
汚されてしまう危険もあるので、このようなクラス構造は、難しいところではある。

リフレクションを使って、無理やり重複をなくすこともできるが、そこまでしてやりたくもない。結局、良い解決策が見つからない。

スニペットで雛形を登録しておくのが最も現実的な解決策かな。
  

Posted by gushwell at 20:33Comments(4)TrackBack(0)

2006年08月22日

C#の名前空間で嵌った

   このエントリーをはてなブックマークに追加 Clip to Evernote
using N1.N2 {
class A { }
}
using N1.N3 {
class B { }
}

は、
using N1 {
using N2 {
class A { }
}
using N3 {
class B { }
}
}

と同じことであり、N3 の中で、N1.N2.A を参照する場合、N2.A と書くこともできる。

そのため、
namespace N1 {
namespace System {
class A { }
}

namespace N3 {
class B : System.Attribute {
}
}
}

は、エラーになってしまう。

N3 内で、System と書いた場合、それは、 N1.System とみなされ、System.Attribute が、N1.System名前空間に無いので、エラーとなる。
これを回避するには、global::System.Attribute とすればOK.

そもそも、System という名前空間を作成すること自体、避けなければいけない。
うっかり、Gushwell.System という名前空間を作ってしまい、嵌まってしまった。
  
Posted by gushwell at 00:00Comments(0)TrackBack(0)

2006年08月21日

C#でのお勧めキャスト

   このエントリーをはてなブックマークに追加 Clip to Evernote
C#でオブジェクトのキャストをする方法は、いろいろあるが、
if ( obj is MyClass ) {
MyClass mc = (MyClass)obj;
... mc に対する処理
}

ではなく、
MyClass mc = obj as MyClass;
if ( mc != null ) {
... mc に対する処理
}

がお勧め。  
Posted by gushwell at 20:50Comments(0)TrackBack(0)

2006年08月18日

独自の構成セクション ハンドラを書く方法

   このエントリーをはてなブックマークに追加 Clip to Evernote
.NET Framework2.0では、独自の構成セクション ハンドラを書く方法が変更になったみたいだ。
今までは、IConfigurationSectionHandler インターフェースを実装し、XmlNodeをハンドリングする必要があったが、.NET Frameworkでは、そういった面倒なコーディングが不要になった。
例えば、以下のようなコードを書けばよい。

 public class MyAppSection : ConfigurationSection {
const string cName = "myName";
[ConfigurationProperty(cName, IsRequired = true)]
[StringValidator(InvalidCharacters = "~!@#$%^&*()[]{}/;'\"|\\",
MinLength = 1, MaxLength = 60)]
public String MyName {
get { return (String)this[cName]; }
}

const string cNumber = "myNumber";
[ConfigurationProperty(cNumber, DefaultValue = 0, IsRequired = false)]
[IntegerValidator(ExcludeRange= false, MinValue = 0, MaxValue = 10000)]
public int MyNumber {
get { return (int)this[cNumber]; }
}
}

上記クラスを作成すれば、以下のような構成セクションを書くことができる。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name ="appSectionGrp">
<section name="myAppSection"
type="Spike.MyAppSection, Spike"/>
</sectionGroup>
</configSections>

<appSectionGrp>
<myAppSection
myName="Value1"
myNumber="543"
/>
</appSection>
</configuration>

この構成セクションを読み込むコードは以下のとおり。

 MyAppSection cs = 
ConfigurationManager.GetSection("appSectionGrp/myAppSection")
as MyAppSection;
string s = cs.MyName;
int n = cs.MyNumber;

プロパティとして見えるのはすばらしいですね。
  
Posted by gushwell at 20:05Comments(0)TrackBack(0)

2006年08月17日

MetaBase.xml ファイルを編集する

   このエントリーをはてなブックマークに追加 Clip to Evernote
IIS の実行中に MetaBase.xml ファイルを編集するには、IIS6.0 の管理コンソールで、サーバーのプロパティを開き、[メタベースの直接編集を有効にする] にチェックをつければ、編集し保存して際に、変更内容は、直ちに有効になる。

IISのサービスを止める必要はないみたいだ。
今まで、これを知らずに、サービスをとめて編集していた。
  
Posted by gushwell at 21:00Comments(0)TrackBack(0)

2006年08月15日

enumの代わり

   このエントリーをはてなブックマークに追加 Clip to Evernote
C#の enum ってとても良い機能だと思うのだけれど、日本人が使おうと思うとちょっと不便。
例えば、
 public enum Gender { Male, Female }

と定義したときに、
"男性","女性" という文字列をどこに定義したらよいのかとても迷う。
ある特定のクラス内でしか使われないのだったら、
 class Person {
public string ToGenderString() { ... }
}

とでも定義しておけばよいのかもしれないが、複数のクラスで利用しようと思うと、この方法だとうまくいかない。
じゃあ、
 public enum Gender { 男性, 女性 }

って定義すれば、
 Gender gender = Gender.女性;

gender.ToString();

で文字列を求められるけど、識別名に日本語使うのは抵抗があるし、「男」、「女」
って文字列にしたい場合には、困ってしまう。

ユーティリティクラスのstaticメソッドで、
  public static string ToGenderString(Gender g) { ... }

と定義すれのも、一つの方法だけれども、それほど良い解決方法だとは思えない。

なんか良い方法はないかな〜 って随分以前に考えた方法は、enumの代わりになるクラスを定義する方法。(ソースは最後に掲載)

これならば、enumとほとんどおんなじ感覚で使えるし、ToString を override しているので、"男性", "女性" という文字列も取得できる。
ToShortStringというメソッド追加すれば、"男", "女" にも対応できる。

列挙型定義するたびに、こんな定義をするのは面倒だけれど、それなりにメリットがあると思う。
ただ、結局日の目を見なかった。

public struct Gender {
private enum EnumGender { Male, Female }
private static Gender _MaleInstance = new Gender(EnumGender.Male);
private static Gender _FemaleInstance = new Gender(EnumGender.Female);
private EnumGender _gender;
private Gender(EnumGender i) {
_gender = i;
}
public static Gender Male {
get {return _MaleInstance; }
}
public static Gender Female {
get { return _FemaleInstance; }
}
public override string ToString() {
return (_gender == EnumGender.Male) ? "男性" : "女性";
}
public static implicit operator int(Gender m) {
return (int)m._gender;
}
}


使い方は、以下のような感じ。

Gender g1 = Gender.Male;
Gender g2 = Gender.Female;
Gender g3 = g1;
Console.WriteLine(g1.ToString());
Console.WriteLine(g2.ToString());
Console.WriteLine(g3.ToString());
int n = g1;
Console.WriteLine(n);

  
Posted by gushwell at 20:30Comments(4)TrackBack(1)

2006年08月10日

C#スニペット

   このエントリーをはてなブックマークに追加 Clip to Evernote
いまさらの感が強いが、プロパティを書くときに、Visual Studio 2005のスニペット機能を使うと便利だ。
prop とタイプして、タブキーを2回押せは、

 private int myVar;

public int MyProperty {
get { return myVar; }
set { myVar = value; }
}

といったコードが挿入される。型や名前は、スニペットの置き換え機能で、素早く変更できる。
  
Posted by gushwell at 21:30Comments(0)TrackBack(0)

2006年08月07日

Webサービス クライアント側のタイムアウト値

   このエントリーをはてなブックマークに追加 Clip to Evernote
Webサービスのクライアント側のタイムアウト値は、WebClientProtocol.Timeout プロパティを設定すれば変更できる。
単位は、ミリ秒なので、3分にしたければ、

MyWebService service = new MyWebService();
service.Timeout = 180000;

となる。Timeout.Infinite に設定すると、タイムアウトせずに待ち続けることになる。
なお、デフォルト値は、100000 ミリ秒だ。

それにしても、.NET Framework の Timeout値の単位って、秒だったり、ミリ秒だったり、分だったりみんなばらばらだなー。
それぞれ事情があるのは分かるのだけれど、TimeSpan型で統一してくれれば良かったのに。。。

service.Timeout = (int)TimeSpan.FromMinutes(3).TotalMilliseconds;

とでも、書こうか???  
Posted by gushwell at 23:06Comments(0)TrackBack(0)