C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: ジェネリクスにおけるinterfaceの暗黙な型変換


(過去ログ 42 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■21891 / inTopicNo.1)  ジェネリクスにおけるinterfaceの暗黙な型変換
  
□投稿者/ KAZUu (1回)-(2008/07/11(Fri) 15:21:00)

分類:[C#] 

C# 3.0 で開発しています。

以下のようなコードがあります。

public class Hoge<T>
{
	public static implicit operator Hoge<T>(T value)
	{
		return null;
	}
}

// OK
{
	Hoge<List<int>> hoge = new List<int>();
}
// OK
{
	Hoge<IList<int>> hoge = new List<int>();
}
// エラー
{
	Hoge<IList<int>> hoge = (IList<int>)new List<int>();
}

List<int>のような具象クラスに対しては暗黙な型変換は期待通りの結果になるのですが、
IList<int>のようなインタフェースに対してはコンパイルエラーになってしまい、期待通りの結果になりません。
IList<int>に限らず自分で適当に定義したインタフェース型に対しても、
インタフェース型からHoge<インタフェース型>への暗黙な型変換でコンパイルエラーが出てしまいます。

どなたか解決策をご教授願えないでしょうか?
ついでに、コンパイルエラーになってしまう理由も教えていただけるとうれしいです。
よろしくお願いします。

引用返信 編集キー/
■21897 / inTopicNo.2)  Re[1]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ Hongliang (282回)-(2008/07/11(Fri) 15:50:17)
CS0552 が直接の原因ですね。
インターフェイスを相手にしたユーザー定義の型変換は許可されていません。

そのものずばりな解決は不可能ですが、用途によっては代替案があるかもしれません。
引用返信 編集キー/
■21899 / inTopicNo.3)  Re[2]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ NyaRuRu (47回)-(2008/07/11(Fri) 16:08:57)
No21897 (Hongliang さん) に返信
> そのものずばりな解決は不可能ですが、用途によっては代替案があるかもしれません。

用途が分からないのでうまくいくかどうか分かりませんが,
考えられる代替案のひとつは,T が interface 型であることを隠してしまうことですかね.

public static class Make
{
    public static Hoge<T> Hoge<T>(T value)
    {
        return value;
    }
}

// OK
Hoge<IList<int>> hoge = Make.Hoge((IList<int>)new List<int>());

引用返信 編集キー/
■21931 / inTopicNo.4)  Re[3]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ KAZUu (2回)-(2008/07/11(Fri) 22:28:53)
2008/07/11(Fri) 22:43:44 編集(投稿者)
Hongliang さん、NyaRuRu さん返信ありがとうございます。

> CS0552 が直接の原因ですね。
> インターフェイスを相手にしたユーザー定義の型変換は許可されていません。

なるほど、やはり言語仕様的に許されていないのですね。
勉強になりました。

> 用途が分からないのでうまくいくかどうか分かりませんが,
> 考えられる代替案のひとつは,T が interface 型であることを隠してしまうことですかね. 

残念ながら用途には合わないのですが、こういった逃げ方もあるのですね。
面白いなぁと思いました。

一応、用途を説明しますと、
先行評価も遅延評価も一緒くたに扱えるインタフェースが欲しいと思いまして、

public interface IWrap<T>
{
	T Value { get; }
}

public abstract class Wrap<T> : IWrap<T>
{
	public abstract T Value { get; }

	public static implicit operator Wrap<T>(T value)
	{
		return new ConcreteWrap<T>(value);
	}
	...
}

public class ConcreteWrap<T> : Wrap<T>
{
	private T _value;
	public override T Value { get { return _value; } }
	...
}

public class LazyWrap<T> : Wrap<T>
...

といったようなクラスを作り、
T から ConcreteWrap<T> にシームレスな変換を実現したかったためです。
ですが、どうやらインタフェースに対しては暗黙な型変換ができないようなので我慢します。

ただ、new ConcreteWrap<int>(0) よりは Make.ConcreteWrap(0) のほうが楽なので、
NyaRuRu さんの案を活用してみたいと思います。

皆様どうもありがとうございました。

解決済み
引用返信 編集キー/
■21935 / inTopicNo.5)  Re[4]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ NyaRuRu (48回)-(2008/07/12(Sat) 02:06:56)
2008/07/12(Sat) 03:24:24 編集(投稿者)

No21931 (KAZUu さん) に返信
>>CS0552 が直接の原因ですね。
>>インターフェイスを相手にしたユーザー定義の型変換は許可されていません。
>
> なるほど、やはり言語仕様的に許されていないのですね。
> 勉強になりました。

いや,単なるバグの可能性もあります.
ちょっと気になったので,一応登録しておきました.そのうち回答があるかと思います.
https://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=355863
解決済み
引用返信 編集キー/
■21937 / inTopicNo.6)  Re[5]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ Hongliang (283回)-(2008/07/12(Sat) 08:32:12)
> いや,単なるバグの可能性もあります.
一応他言語も含めて調べたら、
C# ではコンパイルエラー CS0266。明示的にキャストした場合、変換用関数のコールではなく castclass にコンパイルされるので実行時に InvalidCastException が発生。
VB ではコンパイル成功。ただ実行時は C# と同じく InvalidCastException。
C++/CLI ではコンパイルエラーにならず、明示的・暗黙的にかかわらずキャスト時に op_Implicit/op_Explicit を call するので問題なく動作(C++/CLI はそもそもインターフェイス相手の変換関数の宣言が可能)。

だそうで。いいなぁ C++/CLI。
引用返信 編集キー/
■21942 / inTopicNo.7)  Re[6]: ジェネリクスにおけるinterfaceの暗黙な型変換
□投稿者/ KAZUu (3回)-(2008/07/12(Sat) 13:46:47)
2008/07/12(Sat) 13:56:46 編集(投稿者)
No21935 (NyaRuRu さん) に返信
> いや,単なるバグの可能性もあります.
> ちょっと気になったので,一応登録しておきました.そのうち回答があるかと思います.
> https://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=355863

おお、Mono のコンパイラだと通るのですね。
わざわざ、検証と登録ありがとうございます。
言語仕様ではなくバグとして修正されれば嬉しいのですが。

■No21937 (Hongliang さん) に返信
> C# ではコンパイルエラー CS0266。明示的にキャストした場合、
> 変換用関数のコールではなく castclass にコンパイルされるので実行時に InvalidCastException が発生。
> VB ではコンパイル成功。ただ実行時は C# と同じく InvalidCastException。
> C++/CLI ではコンパイルエラーにならず、
> 明示的・暗黙的にかかわらずキャスト時に op_Implicit/op_Explicit を call するので
> 問題なく動作(C++/CLI はそもそもインターフェイス相手の変換関数の宣言が可能)。

なんと!
明示的なキャストはコンパイル通るので問題ないと思っていたら、
定義したキャスト演算子が呼ばれるわけではないのですね。
たしかに実行したらInvalidCastExceptionでした。がっくり。

C++/CLI なら上手くいくんですねぇ。
他の.NET言語での検証ありがとうございます。


それと軽く報告を。
Hoge<インタフェース型>からインタフェース型へのユーザー定義のキャストも動作しませんでした。
まとめてみると、

public class Hoge<T> {
	public static implicit operator T(Hoge<T> value) {
		return default(T);
	}

	public static implicit operator Hoge<T>(T value) {
		return null;
	}
}

// OK
List<int> list = new List<int>();
Hoge<List<int>> hoge = list;

// CS0266
IList<int> list = new List<int>();
Hoge<IList<int>> hoge = list;

// InvalidCastException
IList<int> list = new List<int>();
Hoge<IList<int>> hoge = (Hoge<IList<int>>)list;

// OK
Hoge<List<int>> hoge = new Hoge<List<int>>();
List<int> list = hoge;

// CS0266
Hoge<IList<int>> hoge = new Hoge<IList<int>>();
IList<int> list = hoge;

// InvalidCastException
Hoge<IList<int>> hoge = new Hoge<IList<int>>();
IList<int> list = (IList<int>)hoge;

という感じです。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -