【发布时间】:2013-02-17 14:55:31
【问题描述】:
我已经把自己编码到一个角落里,希望你能帮助我再次把我挖出来。方向正确。
所以,我已经实现了一个小的 SQLite 包装器,我希望解决方案是通用的(不是我们所有人)。之后,我现在意识到这些类和接口的使用不是很直观,也不是通用的。
让我们从底部开始向上工作。我创建了一个名为DataRow 的类,它作为我的表行的基类。类DataRow 本身只有一个属性Id(因为所有行都需要一个)。这导致以下定义:class DataRow { public int Id { get; set; } }
使用这个DataRow 类,是每个表。对于数据库表,我创建了一个通用接口和一个通用基类。定义如下所示:
internal interface ITable<T>
where T : DataRow, new()
{
T Select(int id);
List<T> Select(List<int> ids);
int Insert(T t);
void Update(T t);
bool Delete(int id);
}
public class Table<T> : ITable<T>
where T : DataRow, new()
{
// Commented out to protect you from a minor case of serious brain damage.
}
此设置允许我创建简洁的定义。事实上,它们往往是相当史诗般的,真的。自豪地说。
public class Car : DataRow
{
public decimal ParkingTicketDebt { get; set; }
public DateTime WhenWifeWillAllowReplacement { get; set; }
public bool CanTransformIntoSomethingAwesome { get; set; }
}
public class Cars : Table<Car> {
// Yep, that's all. You can go home now, folks. There's nothing here. Nothing at all. Especially not a great treasure of gold. Whops... I mean... there's really not. Not that I'm aware of, anyway... I mean, there could be. Not that I wouldn't say if I had any information on this great trasure of gold that might exist. But I know nothing of such an item. I really don't, so you can stop thinking about this great treasure of gold. Since I don't know anything about it, the chance that it even exist is extremely low. Miniscule. I mean, you would probably not find anything, not even if you digged for, like, a really long time. Seven years or something. Oookay. Slowly fading away...
}
您可能注意到也可能没有注意到,我使用Cars 的类类型名称来确定数据库中表的名称。同样,我正在对Car 执行反射,并使用其公共属性名称和类型来获取/设置数据库中的值。是的,我知道我正在编写实体框架的精简版本。这听起来既愚蠢又费时。
无论如何,这里有一个 Cars 类的用法示例,我必须提醒您,我为之感到自豪:
new Cars().Delete(3497); // Note that I have a great number of (expensive) cars.
很好,嗯?一个小问题。这意味着我必须编写强类型代码,具体到数据库中存在的表的数量。而且我不喜欢特定的代码。我喜欢通用代码。
你可能会开始争辩说我做得过火了。那么让我告诉你这个。你说得对,我是矫枉过正!我故意用火焰喷射被坦克碾过的死人。七次。
所以我开始尝试了一下,想出了这个巧妙的解决方案:
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[WebMethod(EnableSession = true)]
public int CreateEmptyRow(string tableName)
{
var tableType = Type.GetType(tableName);
if (tableType == null)
throw new TypeLoadException("Dumbass. That table doesn't exist");
var instance = Activator.CreateInstance(tableType) as ITable<dynamic>;
if (instance == null)
throw new TypeLoadException("Idiot. That type isn't a table");
return instance.Insert(new DataRow());
}
请注意,如果您不知道为什么有人要创建一个空行,我真的可以理解。
那么这有什么问题呢?嗯,它不编译,一方面。这是错误:There is no implicit reference conversion from 'dynamic' to 'DataRow'。在 Google 上搜索得到few results。
问题显然是Activator.CreateInstance(tableType) as ITable<dynamic>。我尝试过Activator.CreateInstance(tableType) as ITable<Table<DataRow>> 之类的方法,但这种尝试给了我这个错误:The type 'DataRow' must be convertible to 'DataRow'。
【问题讨论】:
-
关于改进我的解决方案的建议将获得...奖励
-
既然你已经知道你的 Cars 类实现了
ITable<t>,你需要把它转换成接口吗?你能简单地离开as ITable<dynamic>吗?我发现这篇文章在过去很有帮助:How to Examine and Instantiate Generic Types with Reflection -
更改最少的解决方案,虽然可能不是最快/最有效的,但也是反映您想要调用的方法(而不仅仅是您实例化的类型)
-
@YavgenyP 我觉得一个重要的“DOH”时刻正在建立......
-
是的,虽然我不确定
dynamic是否也很好(再次,性能方面)。最快的使用可能是Table将实现的另一个接口(可以说ITable但没有通用定义)。它将具有与其通用兄弟相同的方法,并且可以在您的CreateEmptyRow方法中对其进行强制转换...
标签: c# .net generics reflection interface