我正在试图弄清楚如何让Generics调用为Type输入一个变量。在下面的调用中,它采用“DAL.Account”类型并且工作正常。
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
我想更改它,以便我可以传递一个变量来代替“DAL.Account”。这样的东西,但我知道这不会起作用,因为你不能将属性作为Type传递。
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
以下是我认为解释我正在尝试做的shell代码段。泛型不是我的强项,所以我正在寻求帮助。无论如何我能做到这一点吗?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
答案 0 :(得分:2)
您正在寻找实例化泛型类型。可以找到一些信息here
这是一个简单的示例,演示如何实例化容量为3的List。以下是一种方法,当您不知道类型时,可以调用该方法来创建泛型:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
以下是一些示例代码,它将向您展示示例方法的工作原理:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
在您的示例中,将GetTable<Criteria.EntityType>()
替换为CreateGenericTableOfType(Criteria.EntityType)
。这将返回您传入的任何类型的通用表。您当然需要正确实现该方法(处理构造函数args,将List更改为表等)。
答案 1 :(得分:0)
我认为你需要稍微改变你的方式,而是使用泛型而不是EntityType属性。也许是下列内容:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}