13

メソッドが BaseObjects のリストを期待している DerivedObjects のリストであるリストを渡すにはどうすればよいですか。リストを変換しています.ToList<BaseClass>()が、もっと良い方法があるかどうか疑問に思っています。2 つ目の問題は、構文が正しくないことです。リスト byref を渡そうとしていますが、エラーが発生しています:'ref' argument is not classified as a variable

これら2つの問題を解決するにはどうすればよいですか? ありがとう。

public class BaseClass { }
public class DerivedClass : BaseClass { }

class Program
{
    static void Main(string[] args)
    {
        List<DerivedClass> myDerivedList = new List<DerivedClass>();
        PassList(ref myDerivedList.ToList<BaseClass>());
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable

        Console.WriteLine(myDerivedList.Count);
    }

    public static void PassList(ref List<BaseClass> myList)
    {
        myList.Add(new DerivedClass());
        Console.WriteLine(myList.Count);
    }
}

解決済み:

これに似た方法で私の問題は解決しました。

public static void PassList<T>(ref List<T> myList) where T : BaseClass
{
    if (myList == null) myList = new List<T>(); 
    // sorry, i know i left this out of the above example.

    var x = Activator.CreateInstance(typeof(T), new object[] {}) as T;
    myList.Add(x);
    Console.WriteLine(myList.Count);
}

この質問と他のSOの質問から助けてくれたすべての人に感謝します。

4

3 に答える 3

19

部分は簡単です。ref参照によって引数を渡すには、基本的に変数でなければなりません。したがって、次のように書くことができます。

List<BaseClass> tmp = myDerivedList.ToList<BaseClass>();
PassList(ref tmp);

...しかし、それは値またはコンテンツ自体には影響しません。myDerivedList

とにかく、メソッド内での値を変更することは決してないため、ここrefでは無意味です。myListパラメーターの値を変更することと、パラメーター値が参照するオブジェクトの内容を変更することの違いを理解することが重要です。詳細については、パラメーターの受け渡しに関する私の記事を参照してください。

リストを渡すことができない理由については、型の安全性を維持するためです。これができると仮定すると、次のように書くことができます。

List<OtherDerivedClass> list = new List<OtherDerivedClass>();
PassList(list);

DerivedClassこれは、 のインスタンスを aに追加しようとすることになりますList<OtherDerivedClass>。これは、バナナの束にリンゴを追加するようなものです...うまくいきません! C# コンパイラは、その安全でない操作の実行を妨げています。バナナの束をフルーツ ボウルとして扱うことはできません。2 つの派生クラスとして, と/の代わりに、与えられたリストにを追加したとします。FruitBaseClassBananaApplePassListApple

// This is fine - you can add an apple to a fruit bowl with no problems
List<Fruit> fruitBowl = new List<Fruit>();
PassList(fruitBowl);

// This wouldn't compile because the compiler doesn't "know" that in PassList
// you're only actually adding an apple.
List<Apple> bagOfApples = new List<Apple>();
PassList(bagOfApples);    

// This is the dangerous situation, where you'd be trying to really violate
// type safety, inserting a non-Banana into a bunch of bananas. But the compiler
// can't tell the difference between this and the previous one, based only on
// the fact that you're trying to convert a List<Banana or Apple> to List<Fruit>
List<Banana> bunchOfBananas = new List<Banana>();
PassList(bunchOfBananas );    

C# 4 では、特定の状況で一般的な差異が許容されますが、根本的に安全でないことを行っているため、この特定のケースでは役に立ちません。ただし、一般的な分散はかなり複雑なトピックです。パラメーターの受け渡しがどのように機能するかをまだ学習しているので、言語の残りの部分に自信が持てるようになるまで、しばらくはそのままにしておくことを強くお勧めします。

于 2011-10-04T04:19:22.933 に答える
3

を保持する必要がある場合はref、次のようにします。

var list = myDerivedList.ToList<BaseClass>();
PassList(ref list);
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable

パラメータの場合、参照refする変数が必要です。オンザフライで作成すると、後でコードで参照するものがないため、意味がありません。

于 2011-10-04T04:18:23.757 に答える
0

まず、提供したコードでは、目的地(参照) myList をまったくref変更しないため、 は必要ありません。もちろん、 byref を使用すると変数が指している場所を変更できるため、エラーが発生しますが、変数を指定せずにを指定します(コンパイラの文句を読んでください;))ref myDerivedList.ToList<..>()

あなたが指摘するように:Co-およびContravarianceについて読んでください-.net 4.0を使用している場合

于 2011-10-04T04:19:41.837 に答える