2

私は答えが単純ではないことを知っています.そして、私はすでにいくつかの(私は醜いと思います)クラッジを使用しています. 私は単にいくつかのエレガントな答えを探しています。

抽象クラス:

public interface IOtherObjects;

public abstract class MyObjects<T> where T : IOtherObjects
{
   ...

   public List<T> ToList()
   {
       ...
   }
}

子供:

public class MyObjectsA : MyObjects<OtherObjectA> //(where OtherObjectA implements IOtherObjects)
{


}

public class MyObjectsB : MyObjects<OtherObjectB> //(where OtherObjectB implements IOtherObjects)
{


}

この時点で T の型が具体的にわからないため、MyObjects (または他の同様のグループ化、ジェネリックまたはその他) のコレクションをループして、 MyObjects基本クラスのToListメソッドを利用することは可能ですか?

編集 具体的な例については、これが発生するたびに、しばらく考えて、代わりに別のことをしたので、現在の要件はありません。でもかなり頻繁に出てくるので、浮かせてみようと思いました。

EDIT @Sara、それは私が気にかけているコレクションの特定のタイプではなく、リストである可能性がありますが、それでも各インスタンスの ToList メソッドは匿名タイプなしでは比較的使用できません)

@aku、本当です。この質問は比較的仮説的なものかもしれませんが、T 個のオブジェクトのリストを取得して操作でき、それらの基本型のみを知っていれば非常に便利です。ToList が BaseType のリストを返すようにすることは、私の回避策の 1 つです。

編集@すべて:これまでのところ、これは私が望んでいた種類の議論でしたが、それは私が疑っていたことをほぼ確認しています. これまでありがとうございましたが、それ以外の方はお気軽に入力してください。

EDIT @Rob、はい、定義されたタイプに対して機能しますが、タイプが IOtherObjects のリストとしてのみ知られている場合は機能しません。

@ロブ再びありがとう。それは通常、私の不器用な回避策でした(無礼ではありません:))。それか、ConvertAll 関数を使用してデリゲートを介してダウンキャストします。問題を理解するために時間を割いていただきありがとうございます。

少し混乱した場合の修飾編集

より正確に言えば、(これの最新の実装を複雑にしすぎた可能性があります):

オブジェクト A から継承した B と C の 2 つのオブジェクト タイプがあるとします。

多くのシナリオが、B のリストまたは C のリスト、またはその他の場合はいずれかのリストから、どこにあるかを示してきましたが、基本クラスにいる場合、あまり具体的でないリストが必要かどうかはわかりません。 A.

上記の例は、List Of Less Specific問題の最新の化身の骨抜きにされた例です。

書く必要のあるコードの量を制限し、他のオプションよりも少し洗練されていると思われるシナリオを考えてみると、通常はそれ自体が提示されています。多かれ少なかれ得た可能性やその他の視点についての議論が本当に欲しかった. ConvertAll() は私が使用した別の回避策であるため、これまで誰も言及していないことに驚いていますが、手元のシナリオには少し冗長すぎます

@ロブ・イェット・アゲインとサラ

ありがとう、しかし、私はすべての静的コンテキストの栄光でジェネリックを理解していると感じており、ここで発生している問題を理解していました.

私たちのシステムの実際の設計とそのジェネリックスの使用法 (私は設計の当事者の 1 人に過ぎなかったので、これは偏見を含まずに言えます) はうまくいきました。それは、私がコア API を扱っているときです。単純に何かを行うのに間違った範囲にいる状況を見つけました。代わりに、好きなよりも少しエレガントではない方法でそれらに対処しなければなりませんでした (いずれかを賢くしようとしました)。またはおそらく怠け者-私はそれらのラベルのいずれかを受け入れます)。

私がクラッジと呼んだものに対する私の嫌悪感は、主に、オブジェクトをベース値に変換するためだけにレコード セットをループする必要があることです。これはパフォーマンス ヒットになる可能性があります。

他の誰かが以前にコーディングでこれに遭遇したかどうか、そして誰かが私よりも賢く、または少なくともエレガントに対処したかどうか疑問に思っていたと思います。

4

7 に答える 7

2

あなたの場合、 MyObjectsA と MyObjectsB には共通の前身がありません。ジェネリック クラスは、共通の基本クラスではなく、さまざまなクラスのテンプレートです。異なるクラスに共通のプロパティが必要な場合は、インターフェイスを使用します。ループ内でToListを呼び出すことはできません。これは、異なるクラスで異なる署名があるためです。特定の型ではなくオブジェクトを返す ToList を作成できます。

于 2008-09-10T04:10:58.407 に答える
2

なぜ MyObjects のコレクションを持っているのですか? リストを持っていない特定の理由はありますか?

于 2008-09-10T04:12:21.573 に答える
1

あなたが持っている場合

class B : A
class C : A

そして、あなたは

List<B> listB;
List<C> listC;

親タイプのリストとして扱いたいこと

次に、を使用する必要があります

List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()
于 2008-09-17T15:27:57.177 に答える
1

OK, I am confused, the following code works fine for me (curiosity got the better of me!):

// Original Code Snipped for Brevity - See Edit History if Req'd

Or have I missed something?

Update Following Response from OP

OK now I am really confused.. What you are saying is that you want to get a List of Typed values from a generic/abstract List? (the child classes therefore become irrelevant).

You cannot return a Typed List if the Types are children/interface implementors - they do not match! You can of course get a List of items that are of a specific type from the abstract List like so:

    public List<OfType> TypedList<OfType>() where OfType : IOtherObjects
    {
        List<OfType> rtn = new List<OfType>();

        foreach (IOtherObjects o in _objects)
        {
            Type objType = o.GetType();
            Type reqType = typeof(OfType);

            if (objType == reqType)
                rtn.Add((OfType)o);
        }

        return rtn;
    }

If I am still off-base here can you please reword your question?! (It doesn't seem like I am the only one unsure of what you are driving at). I am trying to establish if there is a misunderstanding of generics on your part.

Another Update :D

Right, so it looks like you want/need the option to get the typed List, or the base list yes?

This would make your abstract class look like this - you can use ToList to get the concrete type, or ToBaseList() to get a List of the interface type. This should work in any scenarios you have. Does that help?

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<T> ToList()
    {
        return _objects;
    }

    public List<IOtherObjects> ToBaseList()
    {
        List<IOtherObjects> rtn = new List<IOtherObjects>();
        foreach (IOtherObjects o in _objects)
        {
            rtn.Add(o);
        }
        return rtn;
    }
}

Update #3

It's not really a "cludgy" workaround (no disrespect taken) - thats the only way to do it.. I think the bigger issue here is a design/grok problem. You said you had a problem, this code solves it. But if you were expecting to do something like:

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<IOtherObjects> Objects
    { get { return _objects; } }
}
#warning This won't compile, its for demo's sake.

And be able to pick-and-choose the types that come out of it, how else could you do it?! I get the feeling you do not really understand what the point of generics are, and you are trying to get them to do something they are not designed for!?

于 2008-09-10T05:02:47.473 に答える
1

おそらく ToList() メソッドにアクセスすることはできますが、型がわからないのでうまくいきませんか?

foreach(var myObject in myObjectsList)
    foreach(var obj in myObject.ToList())
        //do something

もちろん、これは C# 3.0 でのみ機能します。

var の使用は、リストに含まれる型を知るという要件を取り除くためだけであることに注意してください。Frank のコメントとは対照的に、私は var がタイピングを動的にするという妄想を持っています。

于 2008-09-10T04:17:53.867 に答える
0

私は最近見つけました

List<A>.Cast<B>().ToList<B>()

パターン。

それは私が探していたものを正確に実行します、

于 2008-09-18T23:31:05.323 に答える
-1

ジェネリックは、ランタイム ディスパッチではなく、静的な時間型チェックに使用されます。ランタイム ディスパッチには継承/インターフェイスを使用し、コンパイル時の型保証にはジェネリックを使用します。

interface IMyObjects : IEnumerable<IOtherObjects> {}
abstract class MyObjects<T> : IMyObjects where T : IOtherObjects {}

IEnumerable<IMyObjects> objs = ...;
foreach (IMyObjects mo in objs) {
    foreach (IOtherObjects oo in mo) {
        Console.WriteLine(oo);
    }
}

(明らかに、私はリストよりも列挙型を好みます。)

または、VB のような適切な動的言語を使用するだけです。:-)

于 2008-09-10T04:39:02.367 に答える