locked
How to typecast "Type" object to class without knowing its class RRS feed

  • Question

  • Hi

    there is a class called EntityLIst which works as follows


    EntityList<T> Customers = data.GetList<T>("QuestionBank");
    

    This uses generic parameter T .When I use the class name then it will work fine like if T=cons.QuestionContentType but I want to use as generic only then it throws error during compile time.

    I am loading one assembly  on runtime and using reflection I am getting the class based on user input.From reflection I get the "Type" object instead of class so I am not able to replace T in above.

    Is there any way to pass the Type object which I get during reflection to the above line?

    I can call the above method using Reflection and it works but further down the line I need to type cast and the I get the error.

     Please let me know if there is any way to use it as generics

    Thursday, August 30, 2012 10:33 AM

Answers


  • ...I don't have anything before runtime even the class name, so How can i know the signature....


    That is what is unclear in your scenario.  The original problem is how to implement a type discovered at run time into an existing generic class or method.  A T4 template provides a mechanism for you to substitute the name of your discovered type and compile an assembly at run time.  There is more than one way to generate assemblies at run time, which is what you seem to be doing. 

    My assumption when I had made the suggestion to compile an assembly at run time was that the discovered type would be a "known" type, one which exists in an assembly that could be used to compile your new assembly.  Do you have an existing assembly that contains a definition of the discovered type or not?  Not having a definition of the discovered type in an assembly for Reflection changes everything.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Tuesday, September 4, 2012 12:27 PM
    Moderator
  • So your goal is that the user will select a SharePoint list you don't know at runtime and then will enter directly a linq query ? So you'll get this linq query as text and you'll compile this linq query as some source code. This code source could use also the spmetal generated source code so it can be compiled properly... Your own code won't know nothing about those classes so the ONLY purpose of this would be to let a user to enter directly a query as a linq query.

    If instead you provide the user with a UI that would create a linq query for him against an unknown list then there is likely no point in using linq at all neither the user nor your code will be able to use the spmetal generated classes. So in this case you could just use a CAML query in your code : http://sarangasl.blogspot.fr/2009/10/caml-spquery-in-sharepoint.html and handle this dynamically by inspecting the actual content type you get from this list...

    If you are in between that is the content type is know at desing time but your issue is buliding dynamically a linq query note that you can construct a linq query dynamically (for example you can query from a query before actually running the query sio you can "compose" your query and build it depending on what the user entered on the UI).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    Thursday, September 6, 2012 1:02 PM

All replies

  • Sounds like it would be really convenient if you had a compiled assembly laying around that used the type that you discover at run time in your code.  Try this!  Text Templates.

    http://msdn.microsoft.com/en-us/library/gg251243.aspx  T4 Text Templates

    http://msdn.microsoft.com/en-us/library/dd820620.aspx  Design Time Code Generation

    Hope this helps.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Thursday, August 30, 2012 12:49 PM
    Moderator
  • Hi,

    What is the line that doesn't work ? Usually when using generics you expect a minimal set of features and you can add constraints to the T type to ensure it supports what you need in the generic code you want to write. Try : http://msdn.microsoft.com/en-us/library/d5x73970.aspx

    Else you'll have to apply Rudedog2 suggestions...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    Thursday, August 30, 2012 3:17 PM
  • HI 

    I tried text template but in that also I am getting error .Followoing is the code which I wrote on tt file

    <#@ template debug="false" hostspecific="false" language="C#v3.5" #>
    <#@ output extension=".txt" #>
    <#@ assembly name="System" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="Microsoft.SharePoint.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="Microsoft.SharePoint.Linq" #>
    <#+ 
    public void GetLinqTest(Type test)
    {
      DataContext dataContext = new DataContext(@"http://cons-193b:20000/sites/FCPA");
                StringBuilder stringBuilder = new StringBuilder();
                TextWriter textWriter = new StringWriter(stringBuilder);
                dataContext.Log = textWriter;
    			 EntityList <test> Customers = dataContext.GetList <test> ("QuestionBank");
    }
     
    #>

    The above line Entity list throws error while saving error is "The type or namespace name 'test' could not be found (are you missing a using directive or an assembly reference?)"

    Further For more clarification I am writing down my code 

               

     void getLinq(Type test)
            {

                ////  class    t =(class) Activator.CreateInstance(test);
                //     // Get DataContext from page context
                DataContext dataContext = new DataContext(@"http://cons-193b:20000/sites/FCPA");
                StringBuilder stringBuilder = new StringBuilder();
                TextWriter textWriter = new StringWriter(stringBuilder);
                dataContext.Log = textWriter;

    //I want to make the entry more generic

      EntityList <cons.QuestionBankQuestionBankContentType> Customers = dataContext.GetList <cons.QuestionBankQuestionBankContentType> ("QuestionBank");//This works fine since I am given the proper signature

    // EntityList <test> Customers = dataContext.GetList <test> ("QuestionBank") // throws error "The type or namespace name 'test' could not be found"

    }

    This is the code used in sharepoint to creaty entity collection to run linq queries on it.Now here "cons.QuestionBankQuestionBankContentType" is a partial class which we normally have during compile time.

    In normal scenario we have class objects during compile time for entity list and we use that signature but I am doing something different .In my scenario I am loading the code file during runtime and according to the user input I want to pass the class.Using reflection I get Type object which the entittylist class doesn't take and throws error.

    I then tried reflection and I ran my code as follows 

                

    void getLinq(Type test)
            {

                ////  class    t =(class) Activator.CreateInstance(test);
                //     // Get DataContext from page context
                DataContext dataContext = new DataContext(@"http://cons-193b:20000/sites/FCPA");
                StringBuilder stringBuilder = new StringBuilder();
                TextWriter textWriter = new StringWriter(stringBuilder);
                dataContext.Log = textWriter;

                Assembly ass1 = Assembly.LoadFile(@"D:\VsProjects\LinqToCamlSolution\LinqToCaml\bin\Debug\Microsoft.SharePoint.Linq.dll");
                Type t3 = (Type)(ass1.GetTypes().Where(x => x.Name == "DataContext").First());

                MethodInfo mInfo = t3.GetMethod("GetList");
                MethodInfo generic = mInfo.MakeGenericMethod(test);
                object obj = generic.Invoke(dataContext, new object[] { "QuestionBank" });
    }

    here my  code runs fine with type class but the output of the method is object.In this I am not able to run my linq queries on it since it is not collection.To typecast it we have to use the following line

    EntityList<test> test12 = (EntityList<test>)obj

    which again throws error .Is there any way I can create collection object and run linq on it.


    • Edited by agarwal Friday, August 31, 2012 5:27 AM Given more details
    Friday, August 31, 2012 5:24 AM
  • Check if your version of .NET framework allows you to write and execute ‘EntytyList<dynamic> customers = dataContext.GetList<dynamic>’. Then you should be able to use ‘customers’ and its members in LINQ statements.

    Friday, August 31, 2012 7:52 AM
  • The framework is 3.5 and dynamic is not available
    Friday, August 31, 2012 9:12 AM
  • In this I am not able to run my linq queries on it since it is not collection.

    Cast it to whatever you do know it can be cast to. If it's a collection of objects implementing some interface Ixxx, cast it to IEnumerable<Ixxx>. You can then use it in a query. At worst, you can cast it to IEnumerable<object>. If it could be a collection of values, you can call Cast<object>() instead.

    Friday, August 31, 2012 11:38 AM
  • I tried to cast to Ienumerable<Object>  but it still throw invalid exception.

    EntityList <cons.QuestionBankQuestionBankContentType> Customers = dataContext.GetList <cons.QuestionBankQuestionBankContentType> ("QuestionBank");

    This entitylist is implemented in sharepoint and this just creates an object .It doesn't hit sharepoint and return the result collection.When we create linq query with respect to it then it creates query and hit sharepoint and get the result

    When we try to typecast it then it doesn't get any item except an object that is why I think it throws error.This class is sealed so we can't even inherit it and write our own.

    Any other Idea.


    Friday, August 31, 2012 1:06 PM
  • Does the object implement a specific interface? Do you know anything about it? How do you expect to use it?
    Friday, August 31, 2012 2:34 PM
  • The Text Templates allow you to substitute text into your template dynamically.  The second link that I posted shows you how.

    <#+ 
    public void GetLinqTest(Type test)
    {
      DataContext dataContext = new DataContext(@"http://cons-193b:20000/sites/FCPA");
                StringBuilder stringBuilder = new StringBuilder();
                TextWriter textWriter = new StringWriter(stringBuilder);
                dataContext.Log = textWriter;
    			 EntityList <test> Customers = dataContext.GetList <test> ("QuestionBank");
    }
     
    #>

    Change the method signature so that "Type" is replaced by the name of your type, for which I assume you have an assembly that defines it.

    Your error message is a result of you using a variable, 'test', where you in fact need a type name.  You could the same type of text substitution that you use in the signature.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Friday, August 31, 2012 3:08 PM
    Moderator
  • The Text Templates allow you to substitute text into your template dynamically.


    Aren't text templates used to create the source of a program? The OP mentions using reflection to get the type, so I think the type is not known until runtime.
    Friday, August 31, 2012 3:52 PM
  • The Text Templates allow you to substitute text into your template dynamically.


    Aren't text templates used to create the source of a program? The OP mentions using reflection to get the type, so I think the type is not known until runtime.

    You can do it dynamically at run time.  See the first link that I posted.

    http://msdn.microsoft.com/en-us/library/gg251243.aspx  T4 Text Templates


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/


    Friday, August 31, 2012 5:27 PM
    Moderator
  • Hi

    Can you be more elbaorative because in the below code I am passing test as parameter from another code file.

    Secondly as said I don't have anything before runtime even the class name, so How can i know the signature.Moreover this signature depends on how the user chooses the option which may vary.

    Secondly I have an exe which generates the .cs file and I am compiling this code at runtime to generate the assembly using csharpprovider class.This Exe is spmetal and is of microsoft so I can't do anything in that.This exe generates the code file for the site which I provide as paramter at runtime and after that compile that code file to generate assembly.

    <#+ 
    public void GetLinqTest(Type test)
    {
      DataContext dataContext = new DataContext(@"http://cons-193b:20000/sites/FCPA");
                StringBuilder stringBuilder = new StringBuilder();
                TextWriter textWriter = new StringWriter(stringBuilder);
                dataContext.Log = textWriter;
    			 EntityList <test> Customers = dataContext.GetList <test> ("QuestionBank");
    }
     
    #>

    I have told you the whole scenario so is there any way to get the signature?

    Monday, September 3, 2012 4:36 AM
  • Must use type ?

    You don't use  generic parameter?

    you can instead the type of T?

    Do you know?

    Why should you trouble?

    Tuesday, September 4, 2012 3:46 AM
  • Must use type ?

    You don't use  generic parameter?

    you can instead the type of T?

    Do you know?

    Why should you trouble?


    The OP's problen is that the type is not known at compile, when the he writes his code.  The type is not known until run time.  Hope this helps.

    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Tuesday, September 4, 2012 12:15 PM
    Moderator

  • ...I don't have anything before runtime even the class name, so How can i know the signature....


    That is what is unclear in your scenario.  The original problem is how to implement a type discovered at run time into an existing generic class or method.  A T4 template provides a mechanism for you to substitute the name of your discovered type and compile an assembly at run time.  There is more than one way to generate assemblies at run time, which is what you seem to be doing. 

    My assumption when I had made the suggestion to compile an assembly at run time was that the discovered type would be a "known" type, one which exists in an assembly that could be used to compile your new assembly.  Do you have an existing assembly that contains a definition of the discovered type or not?  Not having a definition of the discovered type in an assembly for Reflection changes everything.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Tuesday, September 4, 2012 12:27 PM
    Moderator
  • Unclear. How will you consume the code you generated at runtime ?

    Usually the approach is :
    - you code against well defined and fixed SharePoint entities so you use spmetal to create the needed classes and you write your code against that
    - or you code against arbitrary data and you use a SharePoint ListItem you'll discover & inspect at runtime

    I'm not sure what is your goal but it seems you expect to be able to generate strong types at runtime and still to be able to use those types in some code you wrote earlier ?

    I would suggest to explain your goal rather than how you plan to achieve your goal (you want to inspect the ContentType for a SharePoint list to know which fields are available ? I wonder if a SharePoint group wouldn"t be better).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    Tuesday, September 4, 2012 5:39 PM
  • Hi Patrice 

    It doesn't require sharepoint blog because it is more of .net. 

    In sharepoint we have spmetal tool to generate entity for sharepoint site.After that we consume these entity classes to do CRUD Operations on sharepoint site.Normally we carry out these type of operation in sharepoint context like webpart,usercontrol,etc which can be used with in sharepoint site.

    If the linq query is complex and there is error then we have to break the query and debug step by step for the output

    I thought exe will be great way to test the query.before writing we can test the query see the output and directly embed in your code 

    This is my main goal.

    I generated the class at runtime using spmetal,loaded the assembly in memory and then I want to create the linq for  sharepoint.Now the issues comes while creating linq,we don't have collection object on which I can run linq.

    I feel this was more of .net in comparison to sharepoint so any suggestion for my query about creating linq will be great.


    Thursday, September 6, 2012 7:18 AM
  • But the linq query you want to create is some code you'll generate also as text file later or do you want some code your wrote *earlier* to consume the classes you just generated ??

    Not sure if you have some special needs but the usual approach is to use spmetal to generate the classes to access your SharePoint server and then  you just use those classes in your project inside your own code before you build and run the final app (this is no different from pretty much every other DB with EF or even every other situation when your strongly typed code can only works against things that were defined previously).

    If you know at least the needed column you could perhaps use an interface and have them implemented by the runtime generated code but once again I don't understand if you have a particular goal of if this is some misunderstanding about how to use spmetal (and in this later case a SharePoint programming group might be better).

    If this is for testing you could include an additional test project that will jsut use the same spmetal generated classes to test your queries as needed ?


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".



    Thursday, September 6, 2012 11:16 AM
  • just now I ma trying with static query but the linq will be the input from the user.If I can run linq code as I want then I will create a interface where user can type linq at runtime and I will execute the code and show the result.

    This is nothing like misunderstanding about the use of spmetal.I just wanted to create a tool that is all which will help me in sharepoint development .

    As I said I don't know anything at compile time. I don't have any class names or field names at compile time.I tried to use expression tree also but in that when I using  expression.lambada method , in that I need to pass class signature where I couldn't get pass through it.

    Let me know if you have anything

    Thursday, September 6, 2012 12:02 PM
  • Maybe in your case you should work with XML data instead of binary objects. Then use LINQ to XML and useful extension functions.

    Thursday, September 6, 2012 12:25 PM
  • So your goal is that the user will select a SharePoint list you don't know at runtime and then will enter directly a linq query ? So you'll get this linq query as text and you'll compile this linq query as some source code. This code source could use also the spmetal generated source code so it can be compiled properly... Your own code won't know nothing about those classes so the ONLY purpose of this would be to let a user to enter directly a query as a linq query.

    If instead you provide the user with a UI that would create a linq query for him against an unknown list then there is likely no point in using linq at all neither the user nor your code will be able to use the spmetal generated classes. So in this case you could just use a CAML query in your code : http://sarangasl.blogspot.fr/2009/10/caml-spquery-in-sharepoint.html and handle this dynamically by inspecting the actual content type you get from this list...

    If you are in between that is the content type is know at desing time but your issue is buliding dynamically a linq query note that you can construct a linq query dynamically (for example you can query from a query before actually running the query sio you can "compose" your query and build it depending on what the user entered on the UI).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    Thursday, September 6, 2012 1:02 PM