.NET Generics の variance サポートと曖昧性
を読んでちょいと気になったこと.
まず基本..NET の型システムは,以下のような型を許す.
public interface ICountable<T> { int Count{ get; } } public class MyCollection : ICountable<string>, ICountable<FileStream> { int ICountable<string>.Count { get { return 1; } } int ICountable<FileStream>.Count { get { return 2; } } }
このように定義された MyCollection は,string として数えられたときには 1 個で,FileStream として数えられたときには 2 個となる.では C# が仮にワイルドカード ICountable<?> をサポートするとして,どちらの実装がバインドされるべき?
実際上の例は .NET の型システムが既に抱え込んでしまっている曖昧性である……ように見える..NET Generics は,ジェネリックデリゲートとジェネリックインターフェイスに関する variance をサポートするわけで,仮に C# 4.0 で,型引数の covariant/contravariant 修飾が解禁されるとして,以下のようなコードはどうしたものか.
public interface ICountable<+T> // Tに関して Covariant { int Count{ get; } } public class MyCollection : ICountable<string>, ICountable<FileStream> { int ICountable<string>.Count { get { return 1; } } int ICountable<FileStream>.Count { get { return 2; } } } public static class Program { static void Main(string[] args) { var col = new MyCollection(); // どちらの ICountable<> 実装を使うか明示する IL 表現は存在するの? var countable = (ICountable<object>)(object)col; Console.WriteLine(countable.Count); } }
気になっているのは,上記コードのような曖昧性を回避したくなったときにどうするか*1.ざっと仕様書を眺め直した範囲では,曖昧なときの意味論とか,曖昧性回避を意図した IL 表現が見つからなかったんだけど,はてさて.
どなたかご存じで?
*1:全部デリゲートにしてしまうというのはひとつの手かも