1

ここで私を避けている別の簡単な質問があります。

私には2つのクラスがあります:

namespace Assets
{
   public class BaseAsset
   {
       // Code here
   }
}

namespace Assets
{
   public class Asset : BaseAsset
   {
       // Code here
   }
}

データベースからAssetのコレクションを返す関数があり、別の関数でその関数を実行してBaseAssetのコレクションを返すようにします。私はこれを試しました:

    public static Collection<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
    {
        return (Collection<BaseAsset>)AssetData.getAssets(CategoryId, UserId, CompanyId);
    }

しかし、ご想像のとおり、機能しません。リストを操作している場合は、次のことができます。

    public static List<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
    {
        return AssetData.getAssets(CategoryId, UserId, CompanyId).Cast<BaseAsset>().ToList();
    }

しかし、私はコレクションを使用したいと思います、誰かがエレガントな解決策を思い付くことができますか?

乾杯、r3plica

4

5 に答える 5

11

これは非常によくある質問です。必要な機能の名前は一般的な共分散です。つまり、「キリンが動物の一種である場合、キリンのリストは動物のリストの一種である」という機能です。

問題は、キリンのリストが一種の動物のリストではないことです。動物のリストにトラを入れることはできますが、キリンのリストにトラを入れることはできません。したがって、キリンのリストは、動物のリストが期待されるコンテキストでは使用できません。

IEnumerable<T>の代わりに使用する必要がある理由は、提供される型引数が両方とも参照型である場合Collection<T>、C# 4 の時点で T で共変であるためです。IEnumerable<T>つまり、どちらも参照型であるため、文字列のシーケンスをオブジェクトのシーケンスとして使用できます。ただし、int のシーケンスは値型であるため、オブジェクトのシーケンスとして使用することはできません。

これが安全な理由は、虎を に挿入する方法がないからIEnumerable<Giraffe>です。

于 2012-12-31T16:58:53.827 に答える
2

の使いやすさが必要な場合は.ToList、独自の.ToCollection拡張メソッドを記述してください。実装は単純である必要があります。IEnumerable<T>, ループを使用して、すべてをコレクションに追加しますAdd

于 2012-12-31T15:03:48.777 に答える
1

問題は、Collection<T>ICollection<T>が不変である (つまりCollection<BaseAsset>、 のサブタイプでもスーパータイプでもないCollection<Asset>) ことです。

この問題は、の代わりにIEnumerable<BaseAsset>またはを返すことで非常に簡単に解決されます。IReadOnlyList<BaseAsset>Collection<BaseAsset>

つまり、次のように記述できます。

public static IEnumerable<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
    return AssetData.getAssets(CategoryId, UserId, CompanyId);
}

キャストは不要になります。

一般に、戻り値と関数パラメーターを指定するときは、具象型 (または)よりもインターフェイス型 ( IList<T>IReadOnlyList<T>ICollection<T>または など) を優先する必要があります。IEnumerable<T>Collection<T>List<T>

于 2012-12-31T15:04:46.613 に答える
0

基本クラスにキャストしようとする代わりに、インターフェイスを抽出してそれを使用してみませんか。

于 2012-12-31T15:04:25.870 に答える
0

Collection<T>クラスには引数として を受け取るコンストラクターがあるため、IList<T>いつでも次のことができます。

Collection<BaseAsset> = new Collection<BaseAsset>(
                                           assetList.Cast<BaseAsset>().ToList());

もちろん、この動作を再利用する必要がある場合は、CastToCollection 拡張機能を作成できます。

public static Collection<TResult> CastToCollection<TResult>(this IEnumerable source)
{
   return new Collection<TResult>(source.Cast<TResult>().ToList());
}
于 2012-12-31T21:13:50.550 に答える