classe genérica usada como restrição ao método genérico em C #?
Pergunta
estou fazendo de errado alguma coisa ou não é possível especificar uma classe genérica como uma restrição a um método genérico?
Eu tenho jogado ao redor com os genéricos e db4o (banco de dados objeto open source) e estou escrevendo um teste programa (ver código abaixo) para armazenar e recuperar algum usuário definido coleções genéricas.
Eu estou tentando escrever um método genérico (veja GetCollectionFromDb abaixo) para recuperar uma coleção especificamente digitada a partir do banco de dados. Infelizmente, o código abaixo retorna um erro do compilador gerado para a linha:
MyCollection1 collection3 =
GetCollectionFromDb<MyCollection1>(Collection1Name);
A mensagem de erro é:
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>'.
Gostaria muito de receber quaisquer sugestões quanto ao que eu possa estar fazendo de errado ou como eu poderia abordar esta questão de forma diferente para alcançar o resultado deisred.
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;
}
}
}
Solução
Basta seguir o 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 traduziria em:
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;
}
O que não é o que você quer desde deriva MyCollection1 fora MyCollectionBase
Outras dicas
Seu tipo não cumpra a restrição. Você fornecido MyCollection1
que deriva MyCollection<Entity1>
. No entanto, isso não significa que ele deriva de MyCollection<MyCollection1>
.
Talvez você quer expressar a restrição mais de dois parâmetros de tipo em vez de um:
private static T GetCollectionFromDb<T, U>(string pCollectionName)
where T : MyCollectionBase<U>
Em seguida, chamá-lo com:
GetCollectionFromDb<MyCollection1, Entity1>(Collection1Name);
Se isso não faz o truque, por favor deixe-nos saber o porquê.