【发布时间】:2009-07-16 18:46:31
【问题描述】:
我目前正在使用 LINQ 和 C#。
我的 LINQ to SQL 模型中有一个表的 DropDownList。
我希望用户能够从下拉列表中选择一个 LINQ 表名。在代码中,我想创建该 LINQ 类的实例,然后运行 Select 或它或我想要的任何其他东西。
如何根据用户选择的字符串中的对象名称创建对象?我是不是一开始就想错了?
【问题讨论】:
标签: c# .net asp.net linq-to-sql
我目前正在使用 LINQ 和 C#。
我的 LINQ to SQL 模型中有一个表的 DropDownList。
我希望用户能够从下拉列表中选择一个 LINQ 表名。在代码中,我想创建该 LINQ 类的实例,然后运行 Select 或它或我想要的任何其他东西。
如何根据用户选择的字符串中的对象名称创建对象?我是不是一开始就想错了?
【问题讨论】:
标签: c# .net asp.net linq-to-sql
你想要Type.GetType(string)和Activator.CreateInstance(Type)。
请注意,Type.GetType(string) 只会在当前执行的程序集和 mscorlib 中查找,除非您指定包括程序集在内的完整类型名称。无论哪种情况,您都需要指定类型名称,包括命名空间。
另一种方法是在调用 Activator.CreateInstance 之前使用Assembly.GetType(string) 直接从字符串中获取类型。
(这里实际上有 很多 种替代方法。如果这些方法都不能帮助您,请发布更多信息,我相信我们可以找到解决方法。)
【讨论】:
由于您使用 ASP.NET 标记了帖子,我假设该列表位于客户端。如果是这种情况,您应该非常小心地信任该数据,并且我不建议直接从用户输入创建类型。您可以将数据用作工厂的输入,然后该工厂可以返回正确的实例(并在您认为合适的情况下处理任何非法输入)。
【讨论】:
详细阐述 Brian Rasmussen 的警告:类型应该受到限制并且需要有意识的设计。最好是“用户可实例化”类型应使用可以通过反射验证的特定自定义属性进行标记。
【讨论】:
对于 LINQ-to-SQL,有一些特定的方法可以从数据上下文中执行此操作;基本上,db.GetTable。这将返回一个ITable,但使用无类型的ITable 有点棘手。至少你可以列举出来……
要获得ITable,您通常需要Type,您可以通过(例如)Assembly.GetType 获得:
using (var ctx = new MyDataContext()) {
string name = "Customer"; // type name
Type ctxType = ctx.GetType();
Type type = ctxType.Assembly.GetType(
ctxType.Namespace + "." + name);
ITable table = ctx.GetTable(type);
foreach(var row in table) {
Console.WriteLine(row); // works best if ToString overridden...
}
}
当然,一旦你有了Type,你就可以使用Activator来创建新的实体实例:
object newObj = Activator.CreateInstance(type);
// TODO: set properties (with reflection?)
table.InsertOnSubmit(newObj);
但如果您想使用属性名称,那也可以:
using (var ctx = new MyDataContext()) {
string name = "Customers"; // property name
ITable table = (ITable) ctx.GetType()
.GetProperty(name).GetValue(ctx, null);
foreach (var row in table) {
Console.WriteLine(row); // works best if ToString overridden...
}
}
运行过滤器 (Where) 等对于无类型数据来说是很棘手的,因为构建 Expression 会很曲折。那时我可能会开始切换到类型化模型...
【讨论】:
跟随 Marc Gravell 的回答。
按照他的建议,我注意到了一个 Cast<TResult> 扩展方法(在 System.Linq 中定义)。
不幸的是,您似乎无法使用 type 实例进行投射:
Type dcType = dc.GetType();
Type type = dcType.Assembly.GetType(String.Format("{0}.{1}", dcType.Namespace, name));
var row = dc.GetTable(type).Cast<type>().SingleOrDefault(i => i.ID == 123);
【讨论】: