Discussion:
InvalidProgramException
(too old to reply)
crazytrain
2005-02-03 12:37:01 UTC
Permalink
C#開発経験4年以上のものですが,(β版からです)
ここに来てInvalidProgramExceptionというものに困らされてます.

環境:Windows XP SP2
VS2002SP3

 以下のクラスをReleaseコンパイルしたdllを参照しているexeを実行すると
InvalidProgramExceptionが発生します.
VisualStudioから実行すると発生しません.
exeから実行するとExceptionが発生します.
 こちらもどこが悪いのかは突き止めてますが,これはC#の文法上
問題あるのでしょうか?
 問題があるのであれば,これは明白にしてもらわないと開発にかなり
支障が生じます.
 Calculateを用いるとExceptionが発生します.4つの配列の
長さは同じものとしてください.

public class TestClass
{
private double[] arrayT;
private double[] arrayS;
private double[] arrayK;
public Swaption(double[] T, double[] K, double[] S)
{
this.arrayT = T;
this.arrayS = S;
this.arrayK = K;
}
public double Calculate(double[] arrayD)
{
double CFPV = 0D;
double LMPV = 0D;
double PVBP = 0D;
double PV = 0D;

for(int i = 0; i < this.arrayT.Length; i++)
{
PV = this.arrayT[i]*arrayD[i];
CFPV += PV*this.arrayK[i];
LMPV += PV*this.arrayS[i];
PVBP += PV;
}
double flatK = (CFPV-LMPV)/PVBP;
return flatK;
}
}
crazytrain
2005-02-03 13:53:04 UTC
Permalink
すみません.
 クラス名とctorが一致していないのはこちらの書き込みミスです.
これは一致させてください.当然コンパイルすら通りません.

 要するにCalculateメソッドがコンパイルのバグを引き起こしているみたいです.この手は原因は大体if/else系です.したがって,
for(int i = 0; i < this.arrayT.Length; i++)
これを
int length = this.arrayT.Lengt;
for(int i = 0; i < length; i++)
とするとExceptionは発生しません.
また,
string strPV = PV.ToString();
for(int i = 0; i < this.arrayT.Length; i++)
とダミーの文字列をインスタンスするとExceptionは発生しません.

あとは無難に配列4つ引数にする方法がありますが,この計算式で
arrayDだけ変更して反復計算して最適解を求めたいとか,または
積分したいなどといった場合があるので,このような引数1つの
メソッドがどうしても必要になります.
 また,Releaseコンパイルではなく,DebugコンパイルならExceptionは
発生しません.
 こんな感じでまだいくつか回避策はありますが,ほとんどの開発者は
こんなことまで考えてコーディングせず,VisualStudioからテストしても
全く気付かないというのが現状ではないでしょうか?
 というか,C#のコンパイラはこの程度なのでしょうか?
Kaoru Kodaka
2005-02-03 13:58:45 UTC
Permalink
$B$+$*$/(B $B$G$9!#(B

On Thu, 3 Feb 2005 04:37:01 -0800
$B!!0J2<$N%/%i%9$r(BRelease$B%3%s%Q%$%k$7$?(Bdll$B$r;2>H$7$F$$$k(Bexe$B$r<B9T$9$k$H(B
$B$&!<$s$H!"$A$g$C$H;n$7$F$_$?$N$G$9$,!"$I$&$b:F8=$G$-$^$;$s$G(B
$B$7$?!#%/%i%$%"%s%HB&$N%3!<%I$K$h$C$F$O=P$J$$$N$G$7$g$&$+!)(B

$B$G$-$l$P!"8=>]$,:F8=$G$-$k40A4$J%3!<%I$rDs<($7$F$b$i$($k$H=u(B
$B$+$j$^$9!#(B
$B!!$3$A$i$b$I$3$,0-$$$N$+$OFM$-;_$a$F$^$9$,!$(B
$B$H$$$&$N$O!)(B

---
MVP kaok = MVP.ChangeMvpCategory("for C# 2004-2005.");
kaok.Web = "http://www.antoine.st/";
crazytrain
2005-02-03 14:21:02 UTC
Permalink
かおくさん,ありがとうございます.

ctorを書き間違えてました.すみません.
とりあえず,今回はTestClassとしてください.
あと,namespaceを適当につけてください.
Testlibとか.
まあ,この辺りはかおくさんにわざわざ言うことではありませんが.
うーんと、ちょっと試してみたのですが、どうも再現できませんで
した。クライアント側のコードによっては出ないのでしょうか?
で,TestClassをReleaseコンパイルでdllにします.

以下のような,簡単なコンソールアプリでdllを参照設定に指定します.

using Testlib
class Class1
{
[STAThread]
static void Main(string[] args)
{
double[] DFValues = new double[6];
DFValues[0] = 0.99999D;
DFValues[1] = 0.88888D;
DFValues[2] = 0.77777D;
DFValues[3] = 0.66666D;
DFValues[4] = 0.55555D;
DFValues[5] = 0.44444D;

double[] termRates = new double[5];
termRates[0] = 0.250D;
termRates[1] = 0.250D;
termRates[2] = 0.250D;
termRates[3] = 0.250D;
termRates[4] = 0.250D;

double[] spreads = new double[5];
spreads[0] = 0.0250D;
spreads[1] = 0.0250D;
spreads[2] = 0.0250D;
spreads[3] = 0.0250D;
spreads[4] = 0.0250D;

double[] strikes = new double[5];
strikes[0] = 0.350D;
strikes[1] = 0.350D;
strikes[2] = 0.350D;
strikes[3] = 0.350D;
strikes[4] = 0.350D;

try
{
TestClass engine = new TestClass(termRates, strikes, spreads);

double K = engine.Calculate(DFValues);

Console.WriteLine(strikeRate.ToString());
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine(ex.StackTrace);
}

Console.WriteLine();
Console.Write("Push [ENTER] Key");
Console.Read();
}
}
crazytrain
2005-02-03 14:27:04 UTC
Permalink
度々すみません.
Post by crazytrain
double K = engine.Calculate(DFValues);
 double strikeRate = engine.Calculate(DFValues);

です.
Kaoru Kodaka
2005-02-03 15:00:15 UTC
Permalink
$B$+$*$/(B $B$G$9!#(B

On Thu, 3 Feb 2005 06:21:02 -0800
ctor$B$r=q$-4V0c$($F$^$7$?!%$9$_$^$;$s!%(B
$BD>$7$F$d$C$F$_$^$7$?!#$&!<$s!"=P$J$$!"$H;W$C$?$i!"$o$?$7$N4D(B
$B6-$O(B Visual Studio .NET 2003 $B$G$7$?!#(B

Visual Studio .NET 2002 $B$^$G$OFq$7$$$G$9$,!"(B.NET Framework
1.0 $B$N4D6-$rMQ0U$7$F;n$7$F$_$^$9!#(B

---
MVP kaok = MVP.ChangeMvpCategory("for C# 2004-2005.");
kaok.Web = "http://www.antoine.st/";
crazytrain
2005-02-03 22:03:03 UTC
Permalink
 かおくさん,ありがとうございます.

 こちらもWinXPSP2+VS2003SP1の環境ではInvalidProgramExceptionが
発生しないことを確認しました.全然大丈夫ですね.
 VS2002で作成したdllをVS2003で作成したコンソールアプリから実行しても
全く問題無しでした.

 ただ,今回の開発環境は.NET Framework1.0なので...

 度重なる書き込みミス大変申し訳ございませんでした.
 わけあって,開発PCは外のネットワークに接続していないので,
インターネットに接続しているPCに直接コピーペーストできませんでした.
 どうか大目に見てください.(ダメ?)
 以後かなり気をつけます.
Kaoru Kodaka
2005-02-03 22:54:28 UTC
Permalink
$B$+$*$/(B $B$G$9!#(B

On Thu, 3 Feb 2005 14:03:03 -0800
$B<jH4$-$r$7$F!"(B.NET Framework 1.0a Redistribute Package $B$r%$(B
$B%s%9%H!<%k$7$F;n$7$F$_$^$7$?!#(B

$B7k2L$H$7$F!"$4;XE&$N8=>]$,H/@8$9$k$3$H$,3NG'$G$-$^$7$?!#(BIL
$B$r$_$?$j!"(BPEVerify $B$G3NG'$7$?$j$7$F$_$^$7$?$,!"FC$K2x$7$$$H(B
$B$3$m$O$J$$$h$&$G$9!#(B

JIT $B$N%P%0$+$J$!!"$H$$$&5$$,$7$^$9$N$G!"$H$j$"$($:(B Microsoft
$B$NJ}$KJs9p$7$F$*$-$^$9!#(B

$BBP=hJ}K!$H$7$F$O!"2?$+$N%@%_!<%3!<%I$NA^F~$G$7$N$0$0$i$$$G$7$g(B
$B$&$+(B....$B!#>C6KE*:v$G$9$_$^$;$s!#(B

---
MVP kaok = MVP.ChangeMvpCategory("for C# 2004-2005.");
kaok.Web = "http://www.antoine.st/";
crazytrain
2005-02-03 23:41:02 UTC
Permalink
あと,こちらでわかっていることをいくつか提示します.

・ループ変数を2つにすると問題発生する場合があります.
(配列arrayT.Length<arrayD.Lengthとする.)

int length = this.arrayT.Lengt;
for(int i = 0, ii = 1; i < length; i++, ii++)
{
PV = this.arrayT[i]*arrayD[ii];
CFPV += PV*this.arrayK[i];
LMPV += PV*this.arrayS[i];
PVBP += PV;
}

・Calculateメソッド内のローカル変数を減らすと問題ありません.
public double Calculate(double[] arrayD)
{
double CFPV = 0D;
double PVBP = 0D;
double PV = 0D;

for(int i = 0; i < this.arrayT.Length; i++)
{
PV = this.arrayT[i]*arrayD[i];
CFPV += PV*this.arrayK[i];
PVBP += PV;
}
double flatK = CFPV/PVBP;
return flatK;
}

コンパイラのバグだと思う(InvalidProgramExceptionの説明より)の
ですが,この程度のコード,普通書きませんか?
まあ,Framework1.1にすれば良いのですがね.
crazytrain
2005-02-04 00:25:02 UTC
Permalink
あと,こうすると大丈夫ですね.

for(int i = 0, ii = 1; i < this.arrayT.Length; i++, ii++)
{
CFPV += this.arrayT[i]*arrayD[ii]*this.arrayK[i];
LMPV += this.arrayT[i]*arrayD[ii]*this.arrayS[i];
PVBP += this.arrayT[i]*arrayD[ii];
}

でも,結合までいかないと発覚しないというのは厄介です.
Kaoru Kodaka
2005-02-04 00:46:18 UTC
Permalink
$B$+$*$/(B $B$G$9!#(B

On Thu, 3 Feb 2005 16:25:02 -0800
$B$G$b!$7k9g$^$G$$$+$J$$$HH/3P$7$J$$$H$$$&$N$OLq2p$G$9!%(B
$B7k9g$H$$$&$N$O!"%/%i%$%"%s%H%"%W%j%1!<%7%g%s$N%S%k%I!"$C$F$3(B
$B$H$G$7$g$&$+!#(B

JIT $B;~$KH/@8$9$k$h$&$G$9$N$G!"(Bngen.exe $B$G%M%$%F%#%V%$%a!<%8(B
$B$***@8@.$9$k$3$H$G$b3NG'$G$-$^$9!#(B

C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705>ngen testclass.dll
Microsoft (R) CLR Native Image Generator - Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
One or more arguments are invalid while compiling method 0x6000002 - TestClass.Calculate.
TestClass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

$B$3$s$J46$8$G!#(B

$BLdBj$N$J$$$H$-$O!"2<$+$iFs9TL\$,I=<($5$l$^$;$s!#(B

---
MVP kaok = MVP.ChangeMvpCategory("for C# 2004-2005.");
kaok.Web = "http://www.antoine.st/";
crazytrain
2005-02-04 00:55:03 UTC
Permalink
かおくさん,ありがとうございます.

なるほど,この手がありましたね!
参考にします.
JIT 時に発生するようですので、ngen.exe でネイティブイメージ
を生成することでも確認できます。
C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705>ngen testclass.dll
Microsoft (R) CLR Native Image Generator - Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
One or more arguments are invalid while compiling method 0x6000002 - TestClass.Calculate.
TestClass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
こんな感じで。
問題のないときは、下から二行目が表示されません。
Kaoru Kodaka
2005-02-07 21:12:03 UTC
Permalink
$B$+$*$/(B $B$G$9!#(B

On Fri, 04 Feb 2005 08:54:28 +1000
Post by Kaoru Kodaka
JIT $B$N%P%0$+$J$!!"$H$$$&5$$,$7$^$9$N$G!"$H$j$"$($:(B Microsoft
$B$NJ}$KJs9p$7$F$*$-$^$9!#(B
$BJs9p$7$F$*$-$^$7$?!#8x<0$J$b$N$G$O$"$j$^$;$s$,!"!V(B.NET
Framework 1.0 $B$NLdBj$@$m$&$H;W$o$l$k!W$H$N2sEz$,$"$j$^$7$?!#(B

$B$H$$$&$3$H$G!"$3$l0J>e$O%5%]!<%H$J$I$***@5<0$J%k!<%H$rDL$8$F!"(B
Microsoft $B$KD4::$r0MMj$9$k$3$H$K$J$k$H;W$$$^$9!#(B

---
MVP kaok = MVP.ChangeMvpCategory("for C# 2004-2005.");
kaok.Web = "http://www.antoine.st/";

Loading...