2012-06-19 62 views
1

我想弄清楚如何可以使一個泛型調用採取變量的類型。在下面的調用中,輸入「DAL.Account」類型,並且工作正常。物業類型作爲通用參數

var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134"); 

我想改變這種狀況,讓我來代替「DAL.Account」的傳遞變量。像這樣的東西,但我知道這將無法正常工作,因爲您無法將屬性作爲類型傳遞。

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; 
     } 
    } 
} 

回答

2

您正在尋找實例化一個泛型類型。一些信息可以發現here

這是一個簡單的例子演示瞭如何實例化一個列表與3這裏的容量是可以調用創建一個通用的,當你不知道該類型的方法:

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)取代。這將返回一個通用的任何類型的通用表。您當然需要正確實現該方法(處理構造函數參數,將List更改爲Table等)。

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> 
{ 
    ... 
}