戻り値が有効であるかどうかを確認する

 
 
 

コマンドおよびメソッドのなかには、無効なコレクションまたはオブジェクトを返すものもあります。 たとえば、シーン内に存在していない項目を返す目的で Find メソッドの使用を試みた場合は、nothing が返されます。後でその無効なオブジェクトまたはコレクションをスクリプト内で使用しようと試みた場合は、エラーが発生します。

戻りオブジェクトが有効であるかどうかを VBScript で判定するには

VBScript では、コマンドまたはメソッドが無効なオブジェクトを返した場合、TypeName 関数が Nothing を返します。

Set oRoot = ActiveSceneRoot
Set oChildren = oRoot.FindChildren
Set oChild = oChildren.Find( "polymsh" )
If TypeName( oChild ) <> "Nothing" Then
	LogMessage "Found " & oChild.Name
Else
	LogMessage "Couldn't find it!"
End If

戻りオブジェクトが有効であるかどうかを JScript で判定するには

JScript では、コマンドまたはメソッドが無効なオブジェクトを返した場合、そのオブジェクトを例外処理で捕捉できます。

var oRoot = ActiveSceneRoot;
var oChildren = oRoot.FindChildren();
var oChild = oChildren.Find( "polymsh" );

try {
	sMessage = "Found " + oChild.Name;
} catch(e) {
	sMessage = "Couldn't find it!";
} finally {
	LogMessage( sMessage );
}

または、次のエラー トラップを使用できます。

var oRoot = ActiveSceneRoot;
var oChildren = oRoot.FindChildren();
var oChild = oChildren.Find( "polymsh" );

if ( oChild == null ) {
	LogMessage( "Couldn't find it!" );
} else {
	LogMessage( "Found " + oChild.Name );
}

空のコレクション

空のコレクションは時には扱いに注意を要することがあります。 コレクションの取得方法(コレクションが返されたときに使用されたコマンドまたはメソッド)に応じて、コレクションの動作は異なります。 たとえば、FindChildren メソッドを使用した場合は、メンバをいっさい持たない有効なコレクションが返されます。

Set oRoot = ActiveSceneRoot
Set oChildren = oRoot.FindChildren( "sphere" )
LogMessage oChildren & " contains " & oChildren.Count & " members."

このコードを、「sphere」というオブジェクトの存在しないシーン上で実行した場合は、以下のようなメッセージが表示されます。

'INFO : "This collection contains 0 members."

しかし、Filter メソッドを使用した場合は有効なコレクションは返されません。

Set oRoot = ActiveSceneRoot
Set oChildren = oRoot.FindChildren
Set oPolyMeshes = oChildren.Filter( "polymsh" )
LogMessage "This collection contains " & oPolyMeshes.Count & " members."

ポリゴンメッシュオブジェクトの存在しないシーン上でこのコード断片を実行すると、スクリプトが異常終了して、以下のようなエラーメッセージが表示されます。

'ERROR : "Object required: 'oPolyMeshes'"

VBScript で NothingCount を組み合わせて使用し、JScript で例外処理を使用することで、これらの種類のエラーを捕捉できます。

コレクションの中に項目が含まれているかどうかを VBScript で判定するには

VBScript の TypeName 関数を使用すると、エラーの送出なしに、有効なコレクションをそのコレクションが返すかどうかをテストできます。

Set oRoot = ActiveSceneRoot
Set oChildren = oRoot.FindChildren
If TypeName( oChildren ) = "Nothing" Then
	LogMessage "This collection is empty."
Else
	LogMessage "This collection has members."
End If

唯一の問題は、そのコレクションが有効なコレクションでメンバを持たない場合に、このテストを実行すると好ましくない結果になることです。

'INFO : "This collection has members."

つまり、以下のようにテストに Count プロパティを含めて、コレクションに項目(コレクション メンバ)が含まれるかどうかを検出する必要があります。

Set oRoot = ActiveSceneRoot
Set oChildren = oRoot.FindChildren( "sphere" )
Set oPolyMeshes = oChildren.Filter( "polymsh" )
Call IsCollectionEmpty( oChildren )
Call IsCollectionEmpty( oPolyMeshes )

Function IsCollectionEmpty( in_collection )
	If TypeName( in_collection ) <> "Nothing" Then
		If in_collection.Count > 0 Then
			LogMessage "Collection has some members"
		Else
			LogMessage "Collection has no members"
		End If
	Else
		LogMessage "Collection is empty"
	End If
End Function
ヒント:

VBScript では、これらの関数は IsNull および IsEmpty と呼ばれます。 これらの関数が実際にテストするのは、コレクションのデータ サブタイプが NullEmpty であるかどうかなので、コレクションが空かどうかをテストする目的でこれらの関数を使用しないでください。 Null および空のデータ タイプおよびサブタイプの詳細については、「「型」について」または msdn2.microsoft.com/en-us/library/9e7a57cf.aspx を参照してください。

コレクションの中に項目が含まれているかどうかを JScript で判定するには

JScript 内に try...catch...finally ステートメントを使用して、エラーを捕捉できます。 たとえば、以下のコード断片中の関数は、Count プロパティを使用して、コレクションが有効であるかどうかを調べ、有効な場合はそのコレクションのメンバがあるかどうかを調べています。

var oRoot = ActiveSceneRoot;
var oChildren = oRoot.FindChildren( "sphere" );
var oPolyMeshes = oChildren.Filter( "surfmsh" );

if ( IsCollectionEmpty(oChildren) ){
	// If empty, then...
}

if ( IsCollectionEmpty(oPolyMeshes) ){
	// If empty, then...
}

function IsCollectionEmpty( in_collection )
{
	var bCollIsEmpty;
	try {
		if( in_collection.Count > 0 ) {
			bCollIsEmpty = false;
		} else {
			bCollIsEmpty = true;
		}
	} catch(e) {
		bCollIsEmpty = true;
	} finally {
		return bCollIsEmpty;
	}
}

失敗する可能性があるコマンドまたはメソッドを呼び出す

メソッドやコマンドの中には、引数やコンテキストが正しくないと失敗するものがあります。 たとえば、Loft オペレータは、入力として 2 つ以上のカーブのコネクション セットを取ります。このオペレータをカーブ以外のコネクション セット(次の例ではトーラス)に適用しようとすると、コマンドが失敗し、スクリプトが中断します。

// This is the incorrect way to apply the Loft operator:
var cnxset = ActiveSceneRoot.AddGeometry( "Torus", "MeshSurface" );
var oplist = ApplyOp( "Loft", cnxset );

//WARNING : 3040-EDIT-GetConnectionSet - Some input objects are invalid ...
//ERROR : Subscript out of range: '[number: 0]' - [line 213 in ...
//ERROR :  - [line 2]


// This is the correct way to apply the Loft operator:
var curve1 = ActiveSceneRoot.AddGeometry( "Arc", "NurbsCurve" );
Translate( curve1, null, null, 2 );
var curve2 = ActiveSceneRoot.AddGeometry( "Arc", "NurbsCurve" );
var cnxset = curve1 + "," + curve2;

var oplist = ApplyOp( "Loft", cnxset );
var msh = oplist.Item( "OutputObjs" );

このエラーは、オペレータに適したタイプのコネクション セットを使用すれば避けることができます。 しかし、スクリプトによっては、入力引数の指定をユーザに依存しなければならない場合もあります。 このような場合は、コマンドを呼び出す前にその入力をテストする必要があります。 たとえば、ユーザが指定したコネクション セットに Loft を適用する場合は、以下のように記述できます。

/*
	This function demonstrates how to provide checks to input objects that
	could cause your scripts to break.
*/
function MakeMesh( in_cnxset )
{
	var allgood;
	// It should be either a string or a selection
	if (typeof(in_cnxset) == 'object') {
		// If it's an object, find out if it's the Selection
		if (ClassName(in_cnxset) == "Selection" ) {
			// Check to make sure that we have at least two items
			if (in_cnxset.Count < 2) {
				LogMessage( "You need at least two curves for Lofting." );
				allgood = false;
			} else {
			// Check each member to make sure that it's a curve
				var e = new Enumerator(in_cnxset);
				for ( ; !e.atEnd(); e.moveNext() ) {
					var chkit = e.item();
					if (chkit.Type != 'crvlist') {
						LogMessage( "You have the right number of objects,"
							+ " but the wrong type!" );
						allgood = false;
						break;
					}
				}
				// At this point, all collection members must have been valid
				allgood = true;
				// Convert Selection to a real connection set (string)
				in_cnxset = in_cnxset.GetAsText();
			}
		} else {
			// There are more possibilities (like XSICollections) that could
			// still be correct that you could test for here, but let's
			// assume that no other kind of object is acceptable
			LogMessage( "What did you give me?!? -- Try again." );
			allgood = false;
		}
	} else {
		// If it's not the Selection object make sure it's a string (that is,
		// a real connection set)
		if (typeof(in_cnxset) == 'string') {
			// Real connection sets should actually report that they are
			// strings. To make sure it's a good connection set, we have to
			// examine each item by splitting the string into an array
			// (assuming that it's delimited by commas ',')
			var mbrs = in_cnxset.split( "," );
			for (var m=0; m<mbrs.length; m++) {
				// Find each item in the scene and make sure that it's
				// really a curve
				var fnd = ActiveSceneRoot.FindChild( mbrs[m] );
				if (fnd != null) {
					// Make sure we found something to test (avoiding errors)
					if (fnd.Type != 'crvlist') {
						// If any member is not a curve, it's no good...
						LogMessage( "This contains non-curve items." );
						allgood = false;
						break;
					}
				}
			}
			// At this point, all members of the connection set must be valid
			allgood = true;
		} else {
			// No other kind of data value is acceptable
			LogMessage( "Ummm -- I need at least 2 curves!" );
			allgood = false;
		}
	}
	
	// Whew! Now can you proceed?...
	if (allgood) {
		var oplist = ApplyOp( "Loft", in_cnxset );
		var msh = oplist.Item( "OutputObjs" );
		return "Success!";
	} else {
		return "Failure :(";
	}
}

時には、テストできない不測の事態が発生することがあります。 呼び出しの失敗が想定される場合は、JScript の try...catch(または、必要に応じて、VBScript の On Error Resume Next)などのステートメントを使用できます。 これで、スクリプトの実行を続けたり、ユーザに情報メッセージを表示することができます。