[英]C#: specialized template method - Error: Type '…' already defines a member called '…' with the same parameter types
I'm quite new to C# and currently developing an application using the EntityFramework. 我是C#的新手,目前正在使用EntityFramework开发应用程序。 I would like to extend the functionality of the database context class, so that I can call a method getPool() so that it hands out the according DbSet member of the class. 我想扩展数据库上下文类的功能,以便可以调用方法getPool(),以便它分发该类的相应DbSet成员。
I need to implement it as a template as it will be later called from other templates, which are just knowing about the (global) database context object and a type T (having a given superclass) for which they shall query the database. 我需要将其实现为模板,因为稍后会从其他模板中调用它们,这些模板仅知道(全局)数据库上下文对象和要查询数据库的类型T(具有给定的超类)。
Here is what I tried (a bit simplified - original example is too complicated): 这是我尝试的方法(有点简化-原始示例太复杂了):
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() where T : TestA {
return (IQueryable<T>)ATests;
}
public IQueryable<T> getPool<T>() where T : TestB {
return (IQueryable<T>)BTests;
}
}
The error message is 错误消息是
Error: Type '...' already defines a member called '...' with the same parameter types . 错误:类型“ ...”已经定义了具有相同参数类型的成员“ ...” 。
And it occurs at the line of the second specialized definition of my template ( public IQueryable<T> getPool<T>() where T : TestB
). 它发生在模板的第二个专门定义的行( public IQueryable<T> getPool<T>() where T : TestB
)。
The question is: How to fix this? 问题是:如何解决此问题?
Unfortunately, in C#, you cannot overload a method by using a generic type constraint like this. 不幸的是,在C#中,您不能通过使用这样的通用类型约束来重载方法。 You will have to give them different names like this 您必须给他们这样的不同名称
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPoolA<T>() where T : TestA {
return (IQueryable<T>)ATests;
}
public IQueryable<T> getPoolB<T>() where T : TestB {
return (IQueryable<T>)BTests;
}
}
Another solution would be to do something like this: 另一个解决方案是做这样的事情:
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() {
return (typeof(T) == typeof(TestA))
? (IQueryable<T>)ATests
: (IQueryable<T>)BTests;
}
}
Now, you can make this even cleaner, since IQueryable<T>
is covariant in T
, you can avoid casting: 现在,您可以使其更加整洁,因为IQueryable<T>
在T
是协变的,因此可以避免强制转换:
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() {
return (typeof(T) == typeof(TestA)) ? ATests : BTests;
}
}
If you want to avoid testing for types you can do something like this: 如果要避免测试类型,可以执行以下操作:
public class TestContext : DbContext
{
readonly Dictionary<Type, object> _sets;
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public TestContext()
{
_sets = new Dictionary<Type, object>
{
{ typeof(TestA), ATests },
{ typeof(TestB), BTests }
}
}
public IQueryable<T> getPool<T>() {
return (IQueryable<T>)_sets[typeof(T)];
}
}
I'd recommend (besides of reading about generics and C# in general) to configure the pool with desired types on run time, store them in dictionaries and use the Type
as key, ie something along the following lines...: 我建议(除了阅读一般性知识和C#外)在运行时为池配置所需的类型,将它们存储在字典中,并使用Type
作为键,即以下几行:
//...
// configuration, maybe factor out to a dedicated class...
private readonly IDictionary<System.Type, IQueryable> m_SupportedPools =
new Dictionary<System.Type, IQueryable>();
// add this queryable, note that type inference works here
public void AddToPool<T>(IQueryable<T> p_Queryable)
{
m_SupportedPools.Add(typeof(T), p_Queryable);
}
public IQueryable<T> GetPool<T>()
{
IQueryable t_Set = null;
if (m_SupportedQueries.TryGetValue(typeof(T), out t_Set)) {
return t_Set as IQueryable<T>;
} else {
return null;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.