DOBON.NET DOBON.NETプログラミング掲示板過去ログ

VB.NET 配列の定数宣言

環境/言語:[OS : Windows XP / 言語 : Visual Basic .NET 2008]
分類:[.NET]

いつもお世話になっています。
しまこ と申します。

VB.NETで配列の定数宣言は不可能なのでしょうか?

以下のコードを実装してエラーが出ています。
Private Const DEFAULTa As String() = {"0", "0", "0", "0", "0", "0"}
エラー:定数は、class、structure、またはarray型ではなく、組み込み型または列挙型でなければなりません。

苦肉の策で変数にする方法も考えました。
Private Shared DEFAULTb As String() = {"0", "0", "0", "0", "0", "0"}

当方が作成しているアプリケーションがコンソールアプリケーションなので、
定数の宣言はConstで統一しております。

出来れば配列もConstで宣言したいのですが、どなたかご教授下さい。
回答、よろしくお願いします。
■No27965に返信(しまこさんの記事)

> エラー:定数は、class、structure、またはarray型ではなく、組み込み型または列挙型でなければなりません。
この通りです。


> 当方が作成しているアプリケーションがコンソールアプリケーションなので、
> 定数の宣言はConstで統一しております。
この因果関係がよく分からない。
定数の宣言はConstというのは分かりますが配列はVBにおいて定数ではありません。
  • 題名: Re[1]: VB.NET 配列の定数宣言
  • 著者: 魔界の仮面弁士
  • 日時: 2011/01/06 21:32:48
  • ID: 27967
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
2011/01/06(Thu) 21:38:23 編集(投稿者)

■No27965に返信(しまこさんの記事)
> VB.NETで配列の定数宣言は不可能なのでしょうか?
> 苦肉の策で変数にする方法も考えました。
> Private Shared DEFAULTb As String() = {"0", "0", "0", "0", "0", "0"}

定数とは異なりますが、ReadOnlyCollection ならば作れます。

Imports System.Collections.ObjectModel
Imports System.Collections.Specialized

Module Module1
 Private ReadOnly DEFAULTa As ReadOnlyCollection(Of String) = _
   Array.AsReadOnly(  New String() {"0", "0", "0", "0", "0"})
 Private ReadOnly DEFAULTb As ReadOnlyCollection(Of String) = _
   New List(Of String)(New String() {"0", "0", "0", "0", "0"}).AsReadOnly()
 'Private ReadOnly DEFAULTc As StringCollection

 Sub Main()
  '読み込みは可能
  MsgBox(DEFAULTa.Count)
  MsgBox(DEFAULTa(0))

  '書き込みはできない
  '
  'DEFAULTa(0) = "1"
  'DEFAULTa = Nothing
 End Sub
End Module
ご回答&サンプル作成ありがとうございます。

>>当方が作成しているアプリケーションがコンソールアプリケーションなので、
>>定数の宣言はConstで統一しております。
> この因果関係がよく分からない。
すみません、言葉足らずでした。
正しくは、
 当方が作成しているアプリケーションがコンソールアプリケーションなので、
 ReadOnlyを使用するとエラー(クラスの明示的なインスタンスを指定しないで、
 共有メソッドまたは共有メンバ初期化子内からのクラスのインスタンスメンバへ
 参照することはできません。)が表示されてしまうので、
 定数の宣言はConstで統一しております。
です。
Sharedキーワードを使用すれば回避できるのですが、「定数」宣言にこだわっていました。


> 定数の宣言はConstというのは分かりますが配列はVBにおいて定数ではありません。
配列はVBにおいて定数ではない、ということはどういう意味ですか。
配列は変数であって、定数にはなりえない ということでしょうか。
勉強不足で申し訳ありませんが、ご教授願います。
■No27971に返信(しまこさんの記事)
> Sharedキーワードを使用すれば回避できるのですが、「定数」宣言にこだわっていました。
コンソールアプリでもインスタンスフィールド/インスタンスプロパティを
利用できますよ。もちろん、そのクラスを New する必要はありますけれども。
あるいは Module を使うようにするとか。
(恐らくは、そういう話では無いのでしょうけれども)


> 配列はVBにおいて定数ではない、ということはどういう意味ですか。
定数として宣言できる型ではない、という事でしょう。

具体的に言えば、Visual Basic において定数として使えるデータ型は、
 使用可能…プリミティブ型、列挙型
 使用不可…クラス、構造体、配列、null許容値型、ジェネリック姿
とされています。

エラーメッセージにも、そのような事が書かれていましたよね。
>> エラー:定数は、class、structure、またはarray型ではなく、組み込み型または列挙型でなければなりません。


ただし、これはあくまでも「Visual Basic における定数の定義」であって、
他の言語では事情が異なる可能性があります。

たとえば 定数として宣言可能な内容を各言語で比較してみると…


【Visual Basic.NET】
 Const c1   As Date      = #12/30/1899#             ' ○OK
'Const c2   As Exception = Nothing                  ' ★NG
 Const c3   As Integer   = 100                      ' ○OK
 Const c4   As String    = "SSS"                    ' ○OK
 Const c5   As Object    = Nothing                  ' ○OK
 Const c6   As Object    = 200                      ' ○OK(As Integer扱い)
 Const c7   As TypeCode  = TypeCode.Char            ' ○OK
'Const c8   As Guid      = Guid.Empty               ' ★NG
'Const c9() As Integer   = {1, 2, 3}                ' ★NG
'Const cA() As Integer   = Nothing                  ' ★NG


【C#.NET】
//const DateTime  c1 = new DateTime(1899, 12, 30); // ★NG(プリミティブな日付型を持たない)
  const Exception c2 = null;                       // ○OK
  const int       c3 = 100;                        // ○OK
  const string    c4 = "SSS";                      // ○OK
  const object    c5 = null;                       // ○OK
//const object    c6 = 200;                        // ★NG
  const TypeCode  c7 = TypeCode.Char;              // ○OK
//const Guid      c8 = Guid.Empty;                 // ★NG
//const int[]     c9 = {1, 2, 3};                  // ★NG
  const int[]     cA = null;                       // ○OK

【JScript.NET】
const c0 : Date      = new Date(1899, 11, 30);     // ○OK
const c1 : DateTime  = new DateTime(1899, 12, 30); // ○OK
const c2 : Exception = null;                       // ○OK
const c3 : Int32     = 100;                        // ○OK
const c4 : String    = "SSS";                      // ○OK
const c5 : Object    = null;                       // ○OK
const c6 : Object    = 200;                        // ○OK
const c7 : TypeCode  = TypeCode.Char;              // ○OK
const c8 : Guid      = Guid.Empty;                 // ○OK
const c9 : Int32[]   = [1, 2, 3];                  // ○OK(ただし要素の編集は可能)
const cA : Int32[]   = null;                       // ○OK
■No27971に返信(しまこさんの記事)

> 正しくは、
>  当方が作成しているアプリケーションがコンソールアプリケーションなので、
>  ReadOnlyを使用するとエラー(クラスの明示的なインスタンスを指定しないで、
>  共有メソッドまたは共有メンバ初期化子内からのクラスのインスタンスメンバへ
>  参照することはできません。)が表示されてしまうので、
>  定数の宣言はConstで統一しております。
> です。
> Sharedキーワードを使用すれば回避できるのですが、「定数」宣言にこだわっていました。
このエラーは特にコンソールアプリケーションだから発生するというものではありません。

以下のサンプルにてSharedメソッドからのインスタンスメンバアクセス以外は
特にエラーになりませんが、どういったコーディングをされているのでしょうか?
(こっちに今2010Expressしかないので他では試していませんが)
ちなみにWindowsFormでも同じです。


Module Module1

    Sub Main()
    '--- 多分こんな呼び方をしている?
        clsA.ShrdMethod()
        '--- インスタンスを作って処理する方法
        Dim a As New clsA
        a.InstMethod()
    End Sub

End Module

Public Class clsA
    '--- Sharedなのでクラス内で唯一作成される
    Private Shared ReadOnly aryShdConst As String() ={"aaaa", "bbbb", "ccccc"}
    '--- インスタンス毎に作成される(内容が変わらないのでインスタンスを
    '--- 複数作った場合は無駄)
    Private ReadOnly aryInstConst As String() = {"dddd", "eeee", "ffff"}

    Public Shared Sub ShrdMethod()
        '--- 共有メソッドから共有メンバアクセスはOK
        For Each strTmp In aryShdConst
            Console.WriteLine(strTmp)
            Console.ReadKey() '--- 確認のため一回ずつ停止
        Next

        '--- 共有メソッドからのインスタンスメンバアクセスはNG
        'For Each strTmp In aryInstConst
        '    Console.WriteLine(strTmp)
        '    Console.ReadKey() '--- 確認のため一回ずつ停止
        'Next
    End Sub

    Public Sub InstMethod()
     '--- インスタンスメソッドからは共有メンバアクセスも可能
        For Each strTmp In aryShdConst
            Console.WriteLine(strTmp)
            Console.ReadKey() '--- 確認のため一回ずつ停止
        Next
        '--- インスタンスメソッドからのインスタンスメンバアクセス
        '--- 問題なし
        For Each strTmp In aryInstConst
            Console.WriteLine(strTmp)
            Console.ReadKey() '--- 確認のため一回ずつ停止
        Next
    End Sub
End Class
  • 題名: Re[4]: VB.NET 配列の定数宣言
  • 著者: しまこ
  • 日時: 2011/01/11 14:15:59
  • ID: 27990
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
■No27977に返信(魔界の仮面弁士さんの記事)

丁寧なご回答ありがとうございます。

>>Sharedキーワードを使用すれば回避できるのですが、「定数」宣言にこだわっていました。
> コンソールアプリでもインスタンスフィールド/インスタンスプロパティを
> 利用できますよ。もちろん、そのクラスを New する必要はありますけれども。
> あるいは Module を使うようにするとか。
> (恐らくは、そういう話では無いのでしょうけれども)
Class と Module の違いが分かっていませんでした。
そもそもSharedキーワードの意味があまり分からずに使っていました。
自分なりに調べたところ、共有化の意味が少し理解できたと思います。


>>配列はVBにおいて定数ではない、ということはどういう意味ですか。
> 定数として宣言できる型ではない、という事でしょう。
> …
言語が違うと、宣言出来る内容がこんなに違うんですね。
分かりやすいサンプルありがとうございます。


本議題の問題は解決しましたので、解決済にさせていただきます。
毎度本当に助かります。
ありがとうございました!
解決済み!
■No27979に返信(shuさんの記事)

ご回答&サンプル作成ありがとうございます。

>>正しくは、
>> 当方が作成しているアプリケーションがコンソールアプリケーションなので、
>> ReadOnlyを使用するとエラー(クラスの明示的なインスタンスを指定しないで、
>> 共有メソッドまたは共有メンバ初期化子内からのクラスのインスタンスメンバへ
>> 参照することはできません。)が表示されてしまうので、
>> 定数の宣言はConstで統一しております。
>>です。
>>Sharedキーワードを使用すれば回避できるのですが、「定数」宣言にこだわっていました。
> このエラーは特にコンソールアプリケーションだから発生するというものではありません。
>
> 以下のサンプルにてSharedメソッドからのインスタンスメンバアクセス以外は
> 特にエラーになりませんが、どういったコーディングをされているのでしょうか?
共有メンバにせず、定数を宣言したかったのでReadOnlyの使用を避けました。
初心者プログラマのため、理解できていない方式を使用したくなかったのです。

お恥ずかしい話ですが、shu様が作ってくださったサンプルで、
共有メンバ及び共有メソッドの意味、Sharedの使い方がわかりました。

とりあえず本議題の問題は解決しましたので、解決済にさせていただきます。

ちなみにソースは以下の様です。
(業務のため、処理内容を変更しています。)

------------------------------------------------------------------------------------------------------------------
Imports System.IO.File

Public Class claA

  Private Const TEST_FILE As String = "C:\Test.txt"
  Private Const MSG_ERR_TITLE As String = "エラー"
  Private Shared ReadOnly DEFAULT_TOTAL As String() = {"0", "0", "0", "0", "0", "0"}
  Private Shared ReadOnly TEXT_ENCODING As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift_jis")

  Shared Sub Main()
    If Not CheckExist(TEST_FILE, "メッセージ内容") Then
      If Not WriteFile(DEFAULT_TOTAL) Then Return
    End If
  End Sub

  Private Shared Function CheckExist(ByVal fn As String, ByVal msg As String) As Boolean
    If Not Exists(fn) Then
      MessageBox.Show(msg, MSG_ERR_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error)
      Return False
    End If
    Return True
  End Function

  Private Shared Function WriteFile(ByVal prm() As String) As Boolean
    Try
      Dim stCsvData As String = String.Join(",", prm)
      System.IO.File.WriteAllText(TEST_FILE, stCsvData & vbCrLf, TEXT_ENCODING)
      Return True
    Catch ex As Exception
      MessageBox.Show(ex.Message, MSG_ERR_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error)
      Return False
    End Try
  End Function

End Class
------------------------------------------------------------------------------------------------------------------
解決済み!
■No27991に返信(しまこさんの記事)
> Private Shared ReadOnly DEFAULT_TOTAL As String() = {"0", "0", "0", "0", "0", "0"}

ReadOnly にしているとはいえ、上記の宣言に対して
 'ReDim claA.DEFAULT_TOTAL(3)      'ReDim で要素数を変更する事はできない
 'claA.DEFAULT_TOTAL = New String(2) {}  '配列を割り当て直す事はできない
 claA.DEFAULT_TOTAL(1) = "2"       '配列のメンバーを操作する事はできる
というコードの実行は許可されますので注意してくださいね。
解決済み!
  • 題名: Re[6]: VB.NET 配列の定数宣言
  • 著者: しまこ
  • 日時: 2011/01/12 11:23:40
  • ID: 27996
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
■No27993に返信(魔界の仮面弁士さんの記事)
> ■No27991に返信(しまこさんの記事)
>>Private Shared ReadOnly DEFAULT_TOTAL As String() = {"0", "0", "0", "0", "0", "0"}
>
> ReadOnly にしているとはいえ、上記の宣言に対して
>  'ReDim claA.DEFAULT_TOTAL(3) 'ReDim で要素数を変更する事はできない
>  'claA.DEFAULT_TOTAL = New String(2) {} '配列を割り当て直す事はできない
>  claA.DEFAULT_TOTAL(1) = "2" '配列のメンバーを操作する事はできる
> というコードの実行は許可されますので注意してくださいね。

返信ありがとうございます。
PG時には気を付けます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板