2013年4月11日木曜日

C#は名前空間とクラス名を区別していない。

何とか二日目です。
(ね、寝るまでが1日だからセーフだよね汗)


本日は「プログラミング」について書きます。


事の発端は3年前・・・んなわけない。
つい先日、ニコニコ動画で↓を見かけたのです。

【自作】SAOようなランチャーを開発しました - SAO Utils

んで、らび爺はというと・・・

「すげぇぇええええ!!」
「C++でこんなことできるんだ~」
「ちょっと入れてみよう!!」

(ゴソゴソ←DL中・・・)

「よっし!(配置完了)」
「Ret's Go !!(exeをぽちっとな)」

「・・・」
「・・・」
「・・・」

なんかエラー出たんですけど・・・orz
まあ、エラーの内容を見るに画像のパスが見つからないだどうのこうの・・・解凍したZIPの中をあさったところ探してる画像自体はあるみたい・・・

きっと画像ファイルを探すときのパスが相対パスと絶対パスで間違ってるんだろう。。。
(開発者の方はC直下とかで開発して、テストとかあんまりしなかったのかな~)

んで、エラーは出るけど何とか動いているようなので、動画に習って動かしてみました。


「SAOの雰囲気が出てていいかも!!」
「画像デスクトップ上に貼れるし」

ところがここで問題が発生。

画像をデスクトップ上に張ったは良いが、消す方法がわからない!!
(なんでもいいやと、エ○画像なんて張るんじゃなかったorz)

ということがあり、使うことを断念(画像はプロセス殺して消したよ!よ!)。



・・・長いな、前置き。巻いていきましょう。



結局何が言いたかったかというと、「上の動画を見たおかげでUI系プログラムを作りたくなったよ。」という話。

ちょうど会社でC#を使ってることもあり、いろいろ調べているうちにWindows Presentation Foundation (WPF)というものがあることを知る。
(英語がtionのあとにtionがあってすごく違和感・・・頭痛が痛い的な・・・)

→VisualStudio2012で開発できるらしく、早速DL(ユーザー登録したので無制限につかえるよ。)し、
ある程度できてきた(今度紹介するかも・・・)ので、そろそろ効率化を図ろうと試しにユーザーコントロール(UserControl)を作成してみることに。

そこで下記のようなソースを作成しました。
(適当に「ソリューション」作って、「プロジェクト」作って、「UserControl」フォルダ作ってその下に↓)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplicationTest.src.UserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}


勘の良い方ならお気づきかと思いますが、これ、自動生成したはずなのにコンパイルエラーになります。

エラー内容は下記:
「WpfApplicationTest.src.UserControl' は '名前空間' ですが、'型' のように使用されています。」

1晩悩みました。
(あっちこっち探したけど、こんなこと起きてる人がそんなにいなかった。)

もともとjavaプログラマーだったらび爺はC#(WPFはC#で書けるから同じ問題を内包してるよ)のイケてない仕様にはまることに。

結論から言うと「C#は名前空間とクラス名を区別していない。」ってのが問題。
だから上みたいなソースだと
名前空間:WpfApplicationTest.src.UserControl
継承元(親)クラス:UserControl

がクラスなのか名前空間なのかわからなくなって、こんなエラーを吐くことに。。。

ちなみに、名前空間(フォルダ名)を下記のように変え、画像のOriginalUserControlの右下に出てるマークの▼を押すと
「名前を'UserControl'から'OriginalUserControl'に変更します。」といっているのでクリック。







こうなります。
ここからコンパイルするとまた「WpfApplicationTest.src.OriginalUserControl' は '名前空間' ですが、'型' のように使用されています。」が出ることに・・・。

この問題、↑の結論がわかっていたら何てことないんだけど、C#初めて間もない自分にはなかなか難題でした。
(片方だけ変更してよとか思ってませんよ。うん。)


難題になった背景には、「javaだとこんなことは起こらない。」から疑いもしなかったこと。
(ちなみにjavaだと、パッケージ名(上で言うUserControlというフォルダ名)は小文字始まりが推奨されているため、そもそもこんなことはしない。)
(さらに、推奨をぶっちぎってパッケージ名と同盟のクラスを継承してもコンパイルエラーにはならない。)


この問題の回避方法は簡単に思いつくところで以下の2つ。

回避策①:名前空間にクラス名で使われているような名前をつけない。
回避策②:親クラスのクラス名をフルパスでかく。

回避策①のソース

namespace WpfApplicationTest.src.OriginalUserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}



回避策②のソース

namespace WpfApplicationTest.src.UserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : System.Windows.Controls.UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}



大体、フレームワークだと②の方法が使われている。
これは、「DLL等で配布したクラスが継承される際にどんな名前空間に置かれるか保障できないため」かと思われる(憶測)。


だいぶ長くなりましたが、まとめると

「○○は'名前空間' ですが、'型' のように使用されています。」的なエラーメッセージが出たら、
「名前空間(フォルダ名)が継承しようとしている親クラスと同じになっていないか」を確認すること。
もしなっているなら、
回避策①:名前空間にクラス名で使われているような名前をつけない。
回避策②:親クラスのクラス名をフルパスでかく。
を行うこと。

原因は「C#は名前空間とクラス名を区別していない。」から。





以上!がんばった。




0 件のコメント:

コメントを投稿

誤字脱字の指摘から、何気ない一言まで気軽な感じでコメントいただけると幸いです。