Pregunta

¿Estoy haciendo algo mal o no es posible especificar una clase genérica como una restricción a un método genérico?

He estado jugando con genéricos y db4o (base de datos de objetos de código abierto) y estoy escribiendo una prueba programa (vea el código a continuación) para almacenar y recuperar algunas colecciones genéricas definidas por el usuario.

Estoy intentando escribir un método genérico (consulte GetCollectionFromDb a continuación) para recuperar una colección específicamente escrita de la base de datos. Desafortunadamente, el siguiente código devuelve un error generado por el compilador para la línea:

 MyCollection1 collection3 =
                  GetCollectionFromDb<MyCollection1>(Collection1Name);

El mensaje de error es:

The type 'GenericsTest.MyCollection1'cannot be used as type parameter 'T'
in the generic type or method 'GenericsTest.Program.GetCollectionFromDb<T>(string)'.
There is no implicit reference conversion from'GenericsTest.MyCollection1' to
'GenericsTest.MyCollectionBase<GenericsTest.MyCollection1>'.

Agradecería cualquier sugerencia sobre lo que podría estar haciendo mal o cómo podría abordar esto de manera diferente para alcanzar el resultado esperado.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Db4objects.Db4o;

 namespace GenericsTest 
    {
        public class Entity1
        {
            public string SomeProperty { get; set; }
        }

        public class Entity2
        {
            public string SomeProperty { get; set; }
        }

        public abstract class MyCollectionBase<T> : Collection<T>
        {
            protected MyCollectionBase() : this("") { }

            protected MyCollectionBase(string pCollectionName) 
            {
                CollectionName = pCollectionName; 
            }

            public string CollectionName { get; set; }
        }

        public class MyCollection1 : MyCollectionBase<Entity1>
        {
            public MyCollection1(string pCollectionName) :
                                          base(pCollectionName) { }

            public void DoSomeWorkOnCollection1() {}
        }

        public class MyCollection2 : MyCollectionBase<Entity2>
        {
            public MyCollection2(string pCollectionName) :
                                          base(pCollectionName) { }

            public void DoSomeWorkOnCollection2() { }
        }

        public class Program
        {
            public static IObjectContainer db = null;

            public static void Main(string[] args)
            {
                const string Collection1Name = "Entity1Collection";
                const string Collection2Name = "Entity2Collection";
                db = Db4oFactory.OpenFile("Test.db");

                Entity1 entity1 = new Entity1();
                MyCollection1 collection1 = new MyCollection1(Collection1Name);
                collection1.Add(entity1);
                db.Store(collection1);

                Entity2 entity2 = new Entity2();
                MyCollection2 collection2 = new MyCollection2(Collection2Name);
                collection1.Add(entity1);
                db.Store(collection2);

                db.Commit();
                db.Close();
                db = Db4oFactory.OpenFile("Test.db");

                MyCollection1 collection3 = 
                       GetCollectionFromDb<MyCollection1>(Collection1Name);
            }

            private static T GetCollectionFromDb<T>(string pCollectionName) 
                                                 where T : MyCollectionBase<T>
            {
                IList<T> queryResult = db.Query((T c) => 
                                         c.CollectionName == pCollectionName);
                if (queryResult.Count != 0) return queryResult[0];

                return null;
            }
        } 
    }
¿Fue útil?

Solución

Solo sigue la T:

    // ...
    {
       //...
       MyCollection1 collection3 = GetCollectionFromDb<MyCollection1>(Collection1Name);

    }

    private static T GetCollectionFromDb<T>(string pCollectionName) where T : MyCollectionBase<T>
    {
        IList<T> queryResult = db.Query((T c) => c.CollectionName == pCollectionName);
        if (queryResult.Count != 0) return queryResult[0];
        return null;
    }

se traduciría en:

    private static MyCollection1 GetCollectionFromDb<MyCollection1>(string pCollectionName) where T : MyCollectionBase< MyCollection1 >
    {
        IList< MyCollection1 > queryResult = db.Query((MyCollection1 c) => c.CollectionName == pCollectionName);
        if (queryResult.Count != 0) return queryResult[0];
        return null;
    }

Lo cual no es lo que desea, ya que MyCollection1 deriva de MyCollectionBase < Entidad1 & Gt; y no MyCollectionBase < MyCollection1 & Gt ;, es por eso que obtuvo el error. Si desea que la restricción funcione, probablemente tendrá que usar un segundo identificador de tipo para expresar el tipo que se está utilizando en la colección genérica.

Otros consejos

Su tipo no satisface la restricción. Ha proporcionado MyCollection1 que se deriva de MyCollection<Entity1>. Sin embargo, eso no significa que se derive de MyCollection<MyCollection1>.

Quizás desee expresar la restricción sobre dos parámetros de tipo en lugar de uno:

private static T GetCollectionFromDb<T, U>(string pCollectionName) 
                                             where T : MyCollectionBase<U>

Luego llámalo con:

GetCollectionFromDb<MyCollection1, Entity1>(Collection1Name);

Si eso no funciona, háganos saber por qué.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top