5

以下のように、インターフェイスとそのインターフェイスを継承する2つのクラスがあります

public interface ILeader
{
    int ID { set; get; }
    string Name { set; get; }
}
public class User : ILeader
{
    public int ID { set; get; }
    public string Name { set; get; }
}
public class Group : ILeader
{
    public int ID { set; get; }
    public string Name { set; get; }
}

ILeader今、タイプのパラメーターと ILeader の IList を持つ 2 つのメソッドがあります。

public void Change(ILeader leader)
{
  //do some thing           
}
public void ChangeList(IList<ILeader> leaderList)
{
  //do some thing           
}

Groupこれで、またはいずれかのオブジェクトUserを Change メソッドに渡すことができ、機能します。Listしかし、 toメソッドで同じことをしようとすると、ChangeListコンパイル時エラーが発生します。

IList<User> userList=new List<User>();
userList.Add(new User { ID=1, Name ="Happy"});

Change(userList[0]);  //this works

ChangeList(userList);  //this throws compile error

エラーは

cannot convert from List<User> to List<ILeader>

ChangeListの両方のリストを渡すことができるようにメソッドを機能させるにはどうすればよいですか?UsersGroups

4

4 に答える 4

6

.Net 4.0 以降を使用している場合は、IList(T) を IEnumerable(T) に変更すると機能します。IList(T) インターフェイスの T パラメータは共変ではなく、IEnumerable(T) インターフェイスの T パラメータは共変です。見る

http://msdn.microsoft.com/en-us/library/dd469487.aspx

詳細な説明のために。

于 2012-11-02T18:50:33.167 に答える
5

IList<T>は共変ではないため、 aを のリストにChangeList追加することを止めるものは何もないことを意味しますが、これは明らかに無効です。GroupUsers

両方の種類のリストを渡すには、リストを次のように変換しますList<ILeader>

ChangeList(userList.Cast<ILeader>().ToList()); 

ただし、これは実際にはリストをキャストしないことに注意してください。各メンバーが のインスタンスである新しいリストが作成されますILeader。これは、ChangeList がGroupリストに a を追加できることを意味します。つまり、それを a に戻すことはできませんでしたList<User>

ChangeListリストにメンバーを追加しない場合は、元に戻すことができます:

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.Cast<User>().ToList();

s以外の項目ChangeList を追加するとUser、変換は失敗します。最良の選択は、結果から sのみを取得することです。User

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.OfType<User>().ToList();  // will ignore anything that's not a `User`
于 2012-11-02T18:51:12.420 に答える
3

実際には、2 番目のメソッドのジェネリック型制約に依存する必要があります。

public void ChangeList<T>(IList<T> leaderList) where T : ILeader
{
  //do some thing           
}

これで、両方のリストを渡すことができます。

于 2012-11-02T18:50:54.040 に答える
2

C# では、クラスは共変ではありません。これは、ここで使用しようとしている機能です。詳細については、この FAQを参照してください。

覚えておくべきいくつかの重要なルール:

この機能は、汎用インターフェイスとデリゲートに対してのみ機能します。バリアント ジェネリック インターフェイスを実装する場合、実装クラスは依然として不変です。C# 4.0 では、クラスと構造体はバリアンスをサポートしていません。したがって、以下はコンパイルされません。

// List<T> implements the covariant interface
// IEnumerable<out T>. But classes are invariant.
List<Person> list = new List<Employee>(); // Compiler error here.

これを機能させるには、 を にキャストする必要がありUserますILeader。でこれを行いuserList.Cast<ILeader>()ます。

于 2012-11-02T18:50:57.037 に答える