"(VS.80)" 有り
IConfigurationSectionHandler インターフェイス (System.Configuration)
"(VS.80)" 無し
IConfigurationSectionHandler インターフェイス (System.Configuration)
で、今度は ConfigurationSection クラスだと、"(VS.80)" が付いている方には「メモ : このクラスは、.NET Framework version 2.0 で新しく追加されたものです。」と書かれているのに "(VS.80)" が付いていない方には書かれていません。
"(VS.80)" 有り
ConfigurationSection クラス (System.Configuration)
"(VS.80)" 無し
ConfigurationSection クラス (System.Configuration)
しかも、よくよく眺めてみると、他にもちらほら違いがあります。
で、更によくよく見ると、"(VS.80)" が付いているページと付いていないページとでは、ページ階層も異なるようで、"(VS.80)" が付いているページは「以前のバージョン」というページの下の方にぶらさがっているようです。
まぁ、だからどうしたと言う訳でもなく、ただそれだけです。
ページによっては、URL から "(VS.80)" を除いたとしても勝手に補完される場合もあるようです。
C# の最短コードは 123 文字です。たぶんこれ以上短くはできないと思われます。
これがそのコードになります。
class P{static void Main(){for(int i=0;i++<100;)System.Console.WriteLine((i%3<1?"Fizz":"")+(i%5<1?"Buzz":i%3<1?"":i+""));}}
改行とスペースを入れて見やすくするとこんな感じです。
class P
{
static void Main()
{
for (int i = 0; i++ < 100; )
System.Console.WriteLine((i % 3 < 1 ? "Fizz" : "") + (i % 5 < 1 ? "Buzz" : i % 3 < 1 ? "" : i + ""));
}
}
最大のポイントは、やはり WriteLine メソッドの引数です。あと、for 文の書き方もポイントですね。普段こんな書き方してたら、怒られても文句言えませんけど ( 笑 )
でも、MSDN には
別のアセンブリ内にある転送先の Type を指定します。このクラスは継承できません。
TypeForwardedToAttribute 属性を使用して、古いアセンブリに対してコンパイルを実行した呼び出し元を妨げずに、あるアセンブリから別のアセンブリに型を移動します。
としか書いてなくて、全く意味がわかりませんでした。
で、ネットで検索してみたら見つかりました。
Mimori's Algorithms tDiary(2007-04-25)
なるほど、例えば、コンソールアプリケーション A からクラスライブラリ A の Hoge クラスと Fuga クラスを利用していたとします。後に Fuga クラスをクラスライブラリ A からクラスライブラリ B へと移動した場合、コンソールアプリケーション A はクラスライブラリ B を参照していないため、そのままでは Fuga クラスを利用できなくなってしまいます。通常、この問題を解決するには、コンソールアプリケーション A の参照設定を修正して再コンパイルする必要があります。しかし、それができない場合に TypeForwardedToAttribute 属性が登場するわけですね。クラスライブラリ A に TypeForwardedToAttribute 属性を付加してクラスライブラリ B の Fuga クラスを指定すれば、コンソールアプリケーション A の参照設定を修正することなく、Fuga クラスを引き続き利用できるわけです。
※ MCP 試験 70-551: UPGRADE: MCAD Skills to MCPD Web Developer by Using the Microsoft .NET Framework
// using System;
// using System.Drawing;
// using System.Drawing.Imaging;
// using System.IO;
static void Main()
{
Image page1 = new Bitmap("C:\\work\\page3.bmp");
Image page2 = new Bitmap("C:\\work\\page3.bmp");
Image page3 = new Bitmap("C:\\work\\page3.bmp");
// TIFF 形式のエンコーダ。
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
Predicate<ImageCodecInfo> tiffEncoderPredicate =
delegate(ImageCodecInfo input)
{
return (input.FormatID == ImageFormat.Tiff.Guid);
};
ImageCodecInfo tiffEncoder = Array.Find(imageEncoders, tiffEncoderPredicate);
// エンコーダのパラメータ。
EncoderParameters tiffEncoderParameters = new EncoderParameters(2);
tiffEncoderParameters.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
tiffEncoderParameters.Param[1] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionNone);
// 作業領域となるメモリストリーム。
MemoryStream tiffStream = new MemoryStream();
// Save メソッドによって、1ページ目が保存され、更に Image オブジェクトとメモリストリームが関連付けられる。
page1.Save(tiffStream, tiffEncoder, tiffEncoderParameters);
// 2ページ目, 3ページ目の保存に使用するエンコーダのパラメータ。
EncoderParameters pageEncoderParameters = new EncoderParameters(2);
pageEncoderParameters.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage);
pageEncoderParameters.Param[1] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionNone);
// 先ほどの Save メソッドで関連付けられたメモリストリームに対して保存される。
// この操作は page1 にフレームを追加するわけではない。
page1.SaveAdd(page2, pageEncoderParameters);
page1.SaveAdd(page3, pageEncoderParameters);
// メモリストリームの内容をファイルに保存する。
File.WriteAllBytes("C:\\work\\test.tif", tiffStream.ToArray());
}
EncoderParameter のインスタンスを生成する際、EncoderValue 列挙値を long にキャストして渡しています。これは int ではなく long にしなければいけません。でないと失敗します。
サンプルなんで Dispose メソッドは呼び出してません。Image, MemoryStream 以外にも、EncoderParameters や EncoderParameter も IDisposable を実装してます。
CodeZine に「ASP.NETのセッションをタイプセーフに取り扱うクラスの作成」という記事が載ってましたが、この方法は僕的にちょっと馴染めなかったもので。
以下、現時点での考えをメモしときます。
セッションステートに保存するオブジェクトは、セッションステートで管理されることを目的として定義されたクラスだけにします。
だから、セッションステートの項目キーはクラスの完全修飾名でいいと考えています。
文字列とかドメインオブジェクト、データセットなんかを直接保存したりはしません。
まず、クラスの完全修飾名を使ってセッションステートを利用するための補助を行う静的クラスを定義しておきます。
項目が見つからなかったり、セッションステートが使えない時 ( IRequiresSessionState インターフェイスを実装していない HTTP ハンドラからの呼び出し等 ) には例外を発生させるようにもします。
SessionStateAdapter(T) クラス
using System;
using System.Web;
using System.Web.SessionState;
/// <summary>
/// 型の完全修飾名を項目キーとしてセッションステートを利用するアダプターです。
/// </summary>
/// <typeparam name="T">セッションステートに保存するインスタンスの型。この型の完全修飾名がセッションステートの項目キーになります。</typeparam>
public static class SessionStateAdapter<T>
{
/// <summary>
/// ジェネリックパラメータ T のインスタンスを現在のセッションステートから取得します。
/// </summary>
/// <returns>ジェネリックパラメータ T のインスタンス</returns>
/// <exception cref="SessionItemNotFoundException">指定した項目がセッションステート内に存在しません。</exception>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
public static T GetItem()
{
HttpSessionState currentSession = SessionStateAdapter<T>.GetSessionState();
object result = currentSession[typeof(T).FullName];
if ((result == null) || !(result is T))
{
throw new SessionItemNotFoundException(typeof(T).FullName);
}
return (T)result;
}
/// <summary>
/// ジェネリックパラメータ T のインスタンスを現在のセッションステートに設定します。
/// </summary>
/// <param name="target">ジェネリックパラメータ T のインスタンス。</param>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
/// <exception cref="System.InvalidOperationException">セッションステートが読み取り専用です。</exception>
/// <exception cref="System.ArgumentNullException">引数 target が null です。</exception>
public static void SetItem(T target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
HttpSessionState currentSession = SessionStateAdapter<T>.GetSessionState();
if (currentSession.IsReadOnly)
{
throw SessionStateAdapter<T>.CreateExceptionForSessionStateIsReadOnly();
}
currentSession[typeof(T).FullName] = target;
}
/// <summary>
/// ジェネリックパラメータ T のインスタンスを現在のセッションステートから削除します。
/// </summary>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
/// <exception cref="System.InvalidOperationException">セッションステートが読み取り専用です。</exception>
public static void RemoveItem()
{
HttpSessionState currentSession = SessionStateAdapter<T>.GetSessionState();
if (currentSession.IsReadOnly)
{
throw SessionStateAdapter<T>.CreateExceptionForSessionStateIsReadOnly();
}
currentSession.Remove(typeof(T).FullName);
}
/// <summary>
/// ジェネリックパラメータ T のインスタンスが現在のセッションステートに存在するかどうかを表す値を返します。
/// </summary>
/// <returns>ジェネリックパラメータ T のインスタンスが現在のセッションステートに存在するかどうかを表す値。</returns>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
public static bool ItemIsExists()
{
HttpSessionState currentSession = SessionStateAdapter<T>.GetSessionState();
return (currentSession[typeof(T).FullName] is T);
}
/// <summary>
/// 現在のセッションステートを取得します。
/// </summary>
/// <returns>現在のセッションステート。</returns>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
private static HttpSessionState GetSessionState()
{
HttpContext currentContext = HttpContext.Current;
HttpSessionState currentSession;
try
{
currentSession = currentContext.Session;
}
catch (Exception ex)
{
throw new InvalidOperationException("セッションステートが利用できません。", ex);
}
if (currentSession == null)
{
throw new InvalidOperationException("セッションステートが利用できません。");
}
return currentSession;
}
/// <summary>
/// セッションステートが読み取り専用であることを示す例外を生成します。
/// </summary>
/// <returns>セッションステートが読み取り専用であることを示す例外。</returns>
private static Exception CreateExceptionForSessionStateIsReadOnly()
{
return new InvalidOperationException("セッションステートが読み取り専用です。");
}
}
セッションステート内に項目が見つからなかった場合にスローされる SessionItemNotFoundException クラスは以下のコードになります。
追加情報として項目のキーを持つことができるようにしてます。
SessionItemNotFoundException クラス
using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
/// <summary>
/// セッションステート内に特定の項目が見つからないことを表す例外。
/// </summary>
[Serializable]
public class SessionItemNotFoundException : Exception
{
#region Constructors
/// <summary>
/// SessionItemNotFoundException クラスの新しいインスタンスを初期化します。
/// </summary>
public SessionItemNotFoundException()
: this(null)
{
}
/// <summary>
/// この例外の原因である項目のキーを指定して、SessionItemNotFoundException クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="key">例外の原因となった項目キー。</param>
public SessionItemNotFoundException(string key)
: this(key, "指定した項目がセッションステート内に存在しません。")
{
}
/// <summary>
/// エラー メッセージ、およびこの例外の原因である項目のキーを指定して、SessionItemNotFoundException クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="key">例外の原因となった項目キー。</param>
/// <param name="message">エラーを説明するメッセージ。</param>
public SessionItemNotFoundException(string key, string message)
: this(key, message, null)
{
}
/// <summary>
/// エラー メッセージ、項目キー、およびこの例外の原因である内部例外への参照を使用して、SessionItemNotFoundException クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="key">例外の原因となった項目キー。</param>
/// <param name="message">例外の原因を説明するエラー メッセージ。</param>
/// <param name="innerException">現在の例外の原因である例外。内部例外が指定されていない場合は、null 参照 (Visual Basic の場合は Nothing)。</param>
public SessionItemNotFoundException(string key, string message, Exception innerException)
: base(message, innerException)
{
this._key = key;
}
/// <summary>
/// シリアル化したデータを使用して、SessionItemNotFoundException クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="context">転送元または転送先に関するコンテキスト情報を含んでいる System.Runtime.Serialization.StreamingContext。</param>
/// <param name="info">スローされている例外に関するシリアル化済みオブジェクト データを保持している System.Runtime.Serialization.SerializationInfo。</param>
/// <exception cref="System.Runtime.Serialization.SerializationException">クラス名が null であるか、または System.Exception.HResult が 0 です。</exception>
/// <exception cref="System.ArgumentNullException">info パラメータが null です。</exception>
protected SessionItemNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this._key = info.GetString("key");
}
#endregion
#region Fields
/// <summary>
/// 例外の原因となった項目キーを取得します。
/// </summary>
private readonly string _key;
#endregion
#region Properties
/// <summary>
/// 例外の原因となった項目キーを取得します。
/// </summary>
public string Key
{
get
{
return this._key;
}
}
#endregion
#region Methods
/// <summary>
/// パラメータ名と追加の例外情報を使用して System.Runtime.Serialization.SerializationInfo オブジェクトを設定します。
/// </summary>
/// <param name="context">転送元または転送先に関するコンテキスト情報。</param>
/// <param name="info">シリアル化されたオブジェクト データを保持するオブジェクト。</param>
/// <exception cref="System.ArgumentNullException">info オブジェクトが null 参照 (Visual Basic の場合は Nothing) です。</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
base.GetObjectData(info, context);
// 追加の例外情報がある場合、ここでパラメータ名と例外情報を info に追加します。
info.AddValue("key", this._key, typeof(string));
}
#endregion
}
ここからが、肝心の「セッションステートで管理されることを目的として定義されたクラス」になります。
業務アプリケーションは大抵の場合、情報の検索だとか、情報の登録、物品の貸出等の複数の機能を持っています。
ここでは、これら一つ一つを "業務" と呼びます。(こうやって呼ぶのって一般的なのかな?)
僕は、画面にビジネスロジックをできるだけ持ち込まないために、ファサードパターンを適用して各業務毎にクラスを用意します。
例えば、ほげ業務には HogeBusiness クラス、ふが業務には FugaBusiness クラスを用意します。
そして、この業務クラスをセッションに保存しておき、複数画面に渡って業務を行います。
そこで、BusinessManager という名前の「セッションステートで管理されることを目的として定義されたクラス」を一つ用意し、そのクラスのフィールドで全ての業務を管理します。
BusinessManager は、Current という読み取り専用のスタティックプロパティを持ちます。
この Current プロパティは、セッションステートを使用してシングルトンパターンのような動きをします。
BusinessManager クラス
using System;
/// <summary>
/// 業務を管理します。
/// </summary>
[Serializable]
public class BusinessManager
{
#region Static Members
#region public static BusinessManager Current
/// <summary>
/// 現在のセッションにて管理されている BusinessManager オブジェクトを取得します。
/// </summary>
/// <exception cref="System.InvalidOperationException">セッションステートが利用できません。</exception>
/// <exception cref="System.InvalidOperationException">セッションステートが読み取り専用です。</exception>
public static BusinessManager Current
{
get
{
BusinessManager currentBusinessManager;
bool isExists = SessionStateAdapter<BusinessManager>.ItemIsExists();
if (isExists)
{
currentBusinessManager = SessionStateAdapter<BusinessManager>.GetItem();
}
else
{
currentBusinessManager = new BusinessManager();
SessionStateAdapter<BusinessManager>.SetItem(currentBusinessManager);
}
return currentBusinessManager;
}
}
#endregion
#endregion
#region Fields
#region private HogeBusiness _hogeBusiness
/// <summary>
/// ほげ業務を取得または設定します。
/// </summary>
private HogeBusiness _hogeBusiness;
#endregion
#region private FugaBusiness _fugaBusiness
/// <summary>
/// ふが業務を取得または設定します。
/// </summary>
private FugaBusiness _fugaBusiness;
#endregion
#endregion
#region Properties
#region public HogeBusiness HogeBusiness
/// <summary>
/// ほげ業務を取得します。
/// </summary>
/// <exception cref="System.InvalidOperationException">ほげ業務が開始されていません。</exception>
public HogeBusiness HogeBusiness
{
get
{
if (this._hogeBusiness == null)
{
throw this.CreateExceptionForNotStartedBusiness("ほげ");
}
return this._hogeBusiness;
}
}
#endregion
#region public FugaBusiness FugaBusiness
/// <summary>
/// ふが業務を取得します。
/// </summary>
/// <exception cref="System.InvalidOperationException">ふが業務が開始されていません。</exception>
public FugaBusiness FugaBusiness
{
get
{
if (this._fugaBusiness == null)
{
throw this.CreateExceptionForNotStartedBusiness("ふが");
}
return this._fugaBusiness;
}
}
#endregion
#endregion
#region Constructors
#region private BusinessManager()
/// <summary>
/// BusinessManager クラスの新しいインスタンスを初期化します。
/// </summary>
private BusinessManager()
{
this.InitializeFields();
}
#endregion
#endregion
#region Methods
#region public void StartHogeBusiness()
/// <summary>
/// ほげ業務を開始します。
/// </summary>
public void StartHogeBusiness()
{
this._hogeBusiness = new HogeBusiness();
}
#endregion
#region public void EndHogeBusiness()
/// <summary>
/// ほげ業務を終了します。
/// </summary>
/// <returns></returns>
public void EndHogeBusiness()
{
this._hogeBusiness = null;
}
#endregion
#region public void StartFugaBusiness()
/// <summary>
/// ふが業務を開始します。
/// </summary>
public void StartFugaBusiness()
{
this._fugaBusiness = new FugaBusiness();
}
#endregion
#region public void EndFugaBusiness()
/// <summary>
/// ふが業務を終了します。
/// </summary>
/// <returns></returns>
public void EndFugaBusiness()
{
this._fugaBusiness = null;
}
#endregion
#region public void EndAllBusiness()
/// <summary>
/// 全ての業務を終了します。
/// </summary>
public void EndAllBusiness()
{
this.InitializeFields();
}
#endregion
#region private void InitializeFields()
/// <summary>
/// フィールドを初期化します。
/// </summary>
private void InitializeFields()
{
this._hogeBusiness = null;
this._fugaBusiness = null;
}
#endregion
#region private void CreateExceptionForNotStartedBusiness(string businessName)
/// <summary>
/// 業務が開始されていないことを表す例外を生成します。
/// </summary>
/// <param name="businessName">業務名。</param>
private Exception CreateExceptionForNotStartedBusiness(string businessName)
{
string message = string.Format("{0}業務は開始されていません。", businessName);
return new InvalidOperationException(message);
}
#endregion
#endregion
}
セッションには BusinessManager のインスタンスが一つだけ格納され、そのインスタンスの各フィールドで業務クラスが管理されます。
セッションで扱う情報は業務クラス以外にもありますので、それらにはまた別の「セッションステートで管理されることを目的として定義されたクラス」を用意します。
それらもまた、Current という読み取り専用のスタティックプロパティを定義し、セッションステートを使用したシングルトンパターンのように実装します。
とりあえず、今の考えはこんな感じです。
他にも、「セッションステートで管理されることを目的として定義されたクラス」を各業務ごとに用意するという方法も考えていて、それはまた少し異なる仕組みとなります ( シングルトンパターンではなくなります ) 。
// コード修正履歴
2007/09/17
・セッションステートが読み取り専用の時は、SessionStateAdapter<T>.SetItem(T) メソッド、SessionStateAdapter<T>.RemoveItem(T) メソッドが例外をスローするよう修正。
2008/12/14
・NotFoundSessionItemException クラスの名称を SessionItemNotFoundException に変更。
こんな感じ。
HogePage.js
// HogePage.html を制御するオブジェクトを生成します。
function HogePage()
{
// Fuga ボタンです。
this._fugaButton = document.getElementById("_fugaButton");
// Piyo ボタンです。
this._piyoButton = document.getElementById("_piyoButton");
// Fuga テキストボックスです。
this._fugaTextBox = document.getElementById("_fugaTextBox");
this._registerEventHandlers();
return this;
}
/* Static Members { */
HogePage.piyo = "Piyo";
/* } Static Members */
/* Methods { */
// 各イベントハンドラを登録します。
HogePage.prototype._registerEventHandlers =
function()
{
var _this = this;
this._fugaButton.onclick = function(){_this._fugaButton_Click();};
this._piyoButton.onclick = function(){_this._piyoButton_Click();};
};
// ふがふがします。
HogePage.prototype._fugaFuga =
function()
{
alert("Hello " + this._fugaTextBox.value + "!!");
};
// ぴよぴよします。
HogePage.prototype._piyoPiyo =
function()
{
alert("Hello " + HogePage.piyo + "!!");
};
/* } Methods */
/* Event Handlers { */
// Fuga ボタンのクリック時に呼び出されます。
HogePage.prototype._fugaButton_Click =
function()
{
this._fugaFuga();
};
// Piyo ボタンのクリック時に呼び出されます。
HogePage.prototype._piyoButton_Click =
function()
{
this._piyoPiyo();
};
/* } Event Handlers */
// ページのロード時に HogePage オブジェクトを生成します。
this.onload =
function()
{
new HogePage();
};
要は、ページに対応する JavaScript を一つのオブジェクトにまとめたという感じ。
イベントハンドラの登録が少し遠回りなコードになってしまったのが残念。
ちなみに、これと対になる HogePage.html はこんな。
HogePage.html
<?xml version="1.0" encoding="shift_jis"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Hoge</title>
<script type="text/javascript" src="HogePage.js"></script>
</head>
<body>
<input id="_fugaTextBox" type="text"/>
<button id="_fugaButton">Fuga</button>
<button id="_piyoButton">Piyo</button>
</body>
</html>
あと、僕の以前の書き方は、このブログの JS ファイルを見るとわかる通り、少し強引に C# っぽく書いていた ^^; ( つーか、Setting~メソッド重複部分多すぎ・・・なんでこんな重複コードを平然と書いてるんだオレ・・・w )