How to cast object to generic class without knowing T - c#

I get my variable from var pi = propertyInfo.GetValue(instance)
this is an object Type. I know all result of this are of type
ObjectSet<TEntity> . I don't know TEntity. TEntity is allways different.
The consuming function looks alike:
BuildClassItem<T>(ObjectSet<T> entities, ... ) where T : class
How can I cast object to ObjectSet ?
I tried alredy this. But I don't know T
public static ObjectSet<T> MyConvert<T>(object myInput) where T : class
{
return (ObjectSet<T>)myInput;
}

You can use System.Linq.Expressions to construct a "trampoline" - a call into a method which is generic. Once you're inside that generic method, then you can start using T naturally when you need to talk about the type. Here I'm using BuildClassItem directly as the target for the trampoline:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Exercise
{
class Program
{
static void Main(string[] args)
{
var obj = GetObjectSet();
//We know obj is an ObjectSet<T> for unknown T
var t = obj.GetType().GetGenericArguments()[0];
var parm = Expression.Parameter(typeof(object));
var objectSet = typeof(ObjectSet<>).MakeGenericType(t);
var method = typeof(Program).GetMethod("BuildClassItem", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(t);
var trampoline = Expression.Lambda(
Expression.Call(null, method, Expression.Convert(parm,objectSet)), new[] {parm});
var dele = (Action<object>) trampoline.Compile();
dele(obj);
Console.WriteLine("Done");
Console.ReadLine();
}
static void BuildClassItem<T>(ObjectSet<T> entities) where T : class
{
Console.WriteLine("We made it!");
}
static object GetObjectSet()
{
return new ObjectSet<string>();
}
}
internal class ObjectSet<T> where T:class
{
}
}
If you have more work to do between finding the type T and calling BuildClassItem you'd still want to put all of that logic inside a generic method in T and construct a void call into it. You can't "say" the name of the type from outside a generic method so you have no way of storing the returned value from your MyConvert function in a correctly typed variable. So you need to move all of the logic into it.

public class ObjectSet<T>
{
}
public static ObjectSet<T> MyConvert<T>(object myInput) where T : class
{
return (ObjectSet<T>)myInput;
}
invoke like this :
ObjectSet<object> get = MyConvert<object>(new ObjectSet<object>());
I'm not got any error , So what error for your case ??
or
public class FOO
{
}
public interface IObjectSet
{
}
public class ObjectSet<T> : IObjectSet
{
}
IObjectSet get = MyConvert<FOO>(new ObjectSet<FOO>());

Related

Shimming object that doesn't have constructor [duplicate]

Take the following class as an example:
class Sometype
{
int someValue;
public Sometype(int someValue)
{
this.someValue = someValue;
}
}
I then want to create an instance of this type using reflection:
Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);
Normally this will work, however because SomeType has not defined a parameterless constructor, the call to Activator.CreateInstance will throw an exception of type MissingMethodException with the message "No parameterless constructor defined for this object." Is there an alternative way to still create an instance of this type? It'd be kinda sucky to add parameterless constructors to all my classes.
I originally posted this answer here, but here is a reprint since this isn't the exact same question but has the same answer:
FormatterServices.GetUninitializedObject() will create an instance without calling a constructor. I found this class by using Reflector and digging through some of the core .Net serialization classes.
I tested it using the sample code below and it looks like it works great:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
namespace NoConstructorThingy
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
myClass.One = 1;
Console.WriteLine(myClass.One); //write "1"
Console.ReadKey();
}
}
public class MyClass
{
public MyClass()
{
Console.WriteLine("MyClass ctor called.");
}
public int One
{
get;
set;
}
}
}
Use this overload of the CreateInstance method:
public static Object CreateInstance(
Type type,
params Object[] args
)
Creates an instance of the specified
type using the constructor that best
matches the specified parameters.
See: http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx
When I benchmarked performance of (T)FormatterServices.GetUninitializedObject(typeof(T)) it was slower. At the same time compiled expressions would give you great speed improvements though they work only for types with default constructor. I took a hybrid approach:
public static class New<T>
{
public static readonly Func<T> Instance = Creator();
static Func<T> Creator()
{
Type t = typeof(T);
if (t == typeof(string))
return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();
if (t.HasDefaultConstructor())
return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();
return () => (T)FormatterServices.GetUninitializedObject(t);
}
}
public static bool HasDefaultConstructor(this Type t)
{
return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}
This means the create expression is effectively cached and incurs penalty only the first time the type is loaded. Will handle value types too in an efficient manner.
Call it:
MyType me = New<MyType>.Instance();
Note that (T)FormatterServices.GetUninitializedObject(t) will fail for string. Hence special handling for string is in place to return empty string.
Good answers but unusable on the dot net compact framework. Here is a solution that will work on CF.Net...
class Test
{
int _myInt;
public Test(int myInt)
{
_myInt = myInt;
}
public override string ToString()
{
return "My int = " + _myInt.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
var obj = ctor.Invoke(new object[] { 10 });
Console.WriteLine(obj);
}
}

Method with Generic Type, set value

I have a method which is something like below and i want to set the value of it with input string.
How would i go about it? Any advice will be greatly appreciated
private static void QueueCheckNAdd<T>(ref T param, string input)
{
param.DoSomethingLikeSetValue(input);
}
for your reference, the generic type is something like int or double
param = (T)(object)Convert.ChangeType(input, typeof(T));
The casts are necessary to convince the compiler that the result is really of type T.
You want param to be generic (i.e., any type), and you expect to be able to call some method on it, correct? Well, you can see the problem there: if param can be any type, there's no way to guarantee that it will have the method DoSomethingLikeSetValue (or whatever). I'm sure you could get fancy with introspection or runtime type coercion, but I think the "clean" way to do what you're looking for is to constrain the type of T to some interface that has the required method (DoSomethingLikeSetValue). Like this:
private static void QueueCheckNAdd<T>(ref T param, string input) where T : IHasSomething {
param.DoSomethingLikeSetValue(input);
}
public interface IHasSomething {
void DoSomethingLikeSetValue(string s);
}
Then you can invoke QueueCheckNAdd generically only if the generic type supports the IHasSomething interface. So you could use it like this:
public class Foo : IHasSomething {
public void DoSomethingLikeSetValue(string s) {
Console.WriteLine(s);
}
}
var f = new Foo();
QueueCheckNAdd<Foo>(f, "hello");
Good practice would be to use interface like described before,
But if you want some fun, you could aslo use the object as a dynamic object, like below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class SMTHG
{
public void DoSomethingLikeSetValue(string input)
{
Console.WriteLine("HEYYYYY!!! DYNAMIC OBJECTS FTW!...\n" + input);
}
}
class Program
{
private static void QueueCheckNAdd<T>(ref T param, string input)
{
dynamic dynamicObject = (dynamic)param;
dynamicObject.DoSomethingLikeSetValue(input);
}
static void Main(string[] args)
{
SMTHG smthg = new SMTHG();
QueueCheckNAdd(ref smthg, "yoyuyoyo");
}
}
}

create a generic wrapper class which will call the methods with lambda expressions

I am struggling to create a generic wrapper class which will call the methods with lambda expressions.
The code looks like this:
The Wrapper Class:
public class Service<T>
{
private T instance;
public Service(T param)
{
this.instance = param;
}
public void Call<U>(Expression<Func<T, U>> aExpression, Action<U> returnClass)
{
var methodCallExpr = aExpression.Body as MethodCallExpression
var lambdaToFunc = Expression.Lambda(methodCallExpr).Compile();
returnClass((U)lambdaToFunc.DynamicInvoke());
}
}
The class which is wrapped:
public class Person
{
public int GetPersonById(int bbb)
{
return bbb;
}
}
The place where I made the call:
var serviceWrapper = new Service<Person>(new Person());
serviceWrapper.Call(x =>x.GetPersonById(2),Console.WriteLine);
I guess i have to atatch the instance of the object which is "instance" to the method expression but I don't know how..
When I run this code i get this exception :
Variable 'x' of type 'AsynCtry.Person' referenced from scope '', but it is not defined.
Is there a way to do this?
You don't need expressions for this - just use delegates directly:
public void Call<U>(Func<T, U> aExpression, Action<U> returnClass)
{
U result = aExpression(this.instance);
returnClass(result);
}
Your method call should function, then:
var serviceWrapper = new Service<Person>(new Person());
serviceWrapper.Call(x => x.GetPersonById(2), u => Console.WriteLine(u));

Property Type as Generic parameter

I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//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;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
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;
}
And here is some sample code that will show you the example method works:
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());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// 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>
{
...
}

Failing to create type dynamically

I am trying to come up with a method factory that looks inside config to get the full name of the type to instantiate and creates that object type dynamically.
Here is my Type and the Interface:
public interface IComponent<T>
{
IEnumerable<T> DataSource {get; set;}
void PerformTask(object executionContext);
}
namespace MyCompany.Components
{
public class ConcreteComponent1<T> : IComponent<T>
{
private IEnumerable<Contact> contactSource = null;
internal ConcreteComponent1() {}
public void PerformTask(object executionContext)
{
this.contactSource = GetSource(executionContext);
foreach(var result in this.contactSource)
{
result.Execute(executionContext);
}
}
public IEnumerable<T> DataSource
{
get { return this.contactSource as IEnumerable<T>; }
set { this.contactSource = (IContactSource)value; }
}
}
}
Factory, resides in the same assembly:
//Factory - Same assembly
public static class ComponentFactory<T>
{
public static IComponent<T> CreateComponent()
{
var assembly = Assembly.GetExecutingAssembly();
object o = assembly.CreateInstance("MyCompany.Components.ConcreteComponent1"); //o is null...
var objectHandle = Activator.CreateInstance(Assembly.GetAssembl(typeof(ComponentFactory<T>)).GetName().FullName, "MyCompany.Components.ConcreteComponent1"); //throws Could not load type from assembly exception.
return o as IComponent<T>;
}
}
So in first case the o is always null.
In the second case when using the Activator class, it throws Type could not be loaded from assembly "MyAssembly". No inner exception. What am I doing wrong?
First of all, actual name of your type is:
MyCompany.Components.ConcreteComponent1`1
It can't be instantiated because you have to specify type parameters:
public static class ComponentFactory<T>
{
public static IComponent<T> CreateComponent()
{
Type generic = Type.GetType("MyCompany.Components.ConcreteComponent1`1");
Type concrete = generic.MakeGenericType(typeof(T));
var objectHandle = Activator.CreateInstance(
concrete,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
null, //here can come ctor params
null);
return objectHandle as IComponent<T>;
}
}
this will work with internal constructor.
I'd say the actual name of your class ConcreteComponent1 is not "MyCompany.Components.ConcreteComponent1" because it includes a generic. Execute
Console.WriteLine(typeof(ConcreteComponent1<T>).FullName);
to see the string representation for your class created by C#.
But why do you define your ConcreteComponent1 class the way you do? Wouldn't it be better to use something like this:
public class ConcreteComponent1 : IComponent<Contact> {
internal ConcreteComponent1() {}
public void PerformTask(object executionContext)
{
this.contactSource = GetSource(executionContext);
foreach(var result in this.contactSource)
{
result.Execute(executionContext);
}
}
public IEnumerable<Contact> DataSource
{
get { return this.contactSource; }
set { this.contactSource = value; }
}
}
This way you can use the expected name you already used in your example and you can remove the extra private field your approach introduces. As your ConcreteComponent1 class doesn't really need any generic functionality this would be a better approach in my opinion.

Categories

Resources