Adding generic constraints at runtime? - c#

I'm pretty stumped with this so if anyone has any ideas. I have the generic method
public void Foo<TClass>(TClass item) where TClass : class
{ }
And I want to call this method from another generic method, but this generic method doesn't have the type constraint "where TClass : class"
public void Bar<T>(T item)
{
this.Foo<T>(item);
}
This doesn't work, I get the error
"The type 'T' must be a reference type in order to use it as parameter 'TClass'"
Which I understand. But my question is this - is there anything I can do with C# syntax in order to "filter" the generic type "T" to pass it to "this.Bar" if it is a class. Something like....
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo<T **as class**>();
}
I realise I could use reflection to call Foo, but this just seems like cheating. Is there something I can do with C# to pass "T" on with the constraint at runtime?
Also - I can't change the constraint on the method "Bar" as it comes from an interface so the constraint has to match the constraint on the interface

The only way to call Foo without reflection, is to cast item to one of the types/classes in its hierarchy (after the proper IsClass check).
Obviously, there's only one type in its hierarchy that you know of a priori: Object.
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo((object) item);
}
Edit :
Also, in one of the comments you said you added the class constraint to be to instantiate T. You don't need that, what you need is the new constraint.

Unfortunately there is no way to do this without changing Bar to have the generic constraint class or using reflection. In order to compile C# must know at compile time that T is indeed a class value. There is no way to use a dynamic test such as typeof(T).IsClass in order to satisfy this compile time constraint.
You mentioned in the question that you can't change Bar but it seems like you are willing to accept the possibility of dynamic failure. Perhaps instead change Foo to not have the constraint but instead throw an exception when T is not a class type

if (typeof(T).IsClass)
{
this.GetType()
.GetMethod("Foo", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public)
.Invoke(this, new object[] { item });
}

I believe there is no way to make it compile. You will have to use reflection to make the call.
Actually. You could cheat if you contain it within a class:
public class Container<T>
{
public Container(T value)
{
Value = value;
}
public T Value { get; private set; }
}
public void Bar<T>(T item)
{
this.Foo<Container<T>>(new Container<T>(item));
}
but this adds one layer you need to call-through and makes the types less clear.

Related

How to define generic extension method that returns type of sub generic

I have a definition like this:
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query)
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
BaseObjectWithDTO defines what type it's DTOs are. Hence I would have thought the by defining E I would have been also defining D.
But IQueryable.ReturnDTO() requires that the generic parameters be specified like this:
IQueryable.ReturnDTO<someEntity, someDTO>();
Which is obviously UGLY.
I tried making this IQueryable<E> as this IQueryable<BaseObjectWithDTO<D, int>> instead but then this has nothing as the in of the func because it won't take a type inferred by the Generic Parameter of the IQuerayble:
var projection = Expression.Lambda<Func<E, D>>(memberInitExpression, itemParam);
Ideas on how to get this to not require the types be passed every time?
Unfortunately, C#'s generic type inference system isn't as powerful as it could be. If you include a parameter involving D, then it can infer it. For example...
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query,
IQueryable<BaseObjectWithDTO<D, int>> dummy)
// now you can do...
myQueryable.ReturnDTO(myQueryable);
// instead of
myQueryable.ReturnDTO<BaseObjectWithDTO<BaseDTO, int>, BaseDTO>();
It's confusing and arguably a poor design to pass the same variable in twice, but it's better (IMHO) than having to explicitly specify the types or resort to reflection or other runtime techniques to extract the types (when that's otherwise unnecessary).
Since you aren't actually going to use the dummy parameter, it doesn't matter what the value is, as long as the type is right, so you might still be able to use this at the end of a query chain, e.g. this will still return the expected value, even though you pass in two different IQueryables.
var result = otherQueryable.Where(...).ReturnDTO(otherQueryable);
If you prefer to be slightly less cryptic, you could make the dummy parameter D dummy, and then e.g. myQueryable.ReturnDTO(default(SomeDTO)) (here using default as a clear way of getting a null or default value without having a reference to a variable/field/property of that type) if you prefer.
I don't think it is possible as you currently have it designed, this MSDN page states that type inference is not possible in this scenario:
The same rules for type inference apply to static methods and instance
methods. The compiler can infer the type parameters based on the
method arguments you pass in; it cannot infer the type parameters only
from a constraint or return value.
That means you have to pass in a parameter of your type to this method for the compiler to be able to infer the types.
You have to specify the type, but it doesn't have to be done explicitly in the q.Return<E,D>(). There are ways that you can pass specify the type parameter so that it can be inferred implicitly. To do that, you'll need to change the signature a bit.
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query, D dtoTypeExample = default(D))
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
Now, even though there's a default parameter, the compiler won't be able to get it unless you pass some argument in. The thing you pass in doesn't have to be used by the method in any other way though. For example, assume you have:
public class ProductDTO : BaseDTO {
public static ProductDTO Empty { get { return new ProductDTO(); } }
}
public class Product : BaseObjectWithDTO<ProductDTO,int> {
public static IQueryable<Product> QuerySource { get; set; }
}
You could then call:
ProductDTO dto = Product.QuerySource.ReturnDTO(ProductDTO.Empty);
I'm not saying that this is necessarily a good idea, but you could do it. Also, it doesn't have to be the actual type that you pass in - you just need to pass in something that's close enough for the compiler to infer the intended type. For example, you could have a signature like:
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query, Func<D,D> dtoIdentity = default(Func<D,D>))
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
then if you have:
public class ProductDTO : BaseDTO {
public static ProductDTO Identity(ProductDTO dto){ return dto; };
}
public class Product : BaseObjectWithDTO<ProductDTO,int> {
public static IQueryable<Product> QuerySource { get; set; }
}
You could then call:
ProductDTO dto = Product.QuerySource.ReturnDTO(ProductDTO.Identity);
This might make more semantic sense to some, but it's somewhat subjective. Once again, I'm not recommending this, just saying that you can do it. If you do decide to do it though, it might save you a little work to have a self-referential generic base (Warning: Eric Lippert discourages this kind of thing). But anyway, your design would then look like:
public abstract class BaseDTO<T> where T : BaseDTO<T>, new()
{
public static T Empty { get { return new T(); } }
}
public class ProductDTO : BaseDTO<ProductDTO> { }
You could also add the type constraint to your ReturnDTO method if you want to enforce an invariant that all DTOs were then self-referential derivatives of BaseDTO<T> with public parameterless constructors. But, if you're trying to write what would conventionally be considered good code you probably won't do any of this and you'll just close your eyes and explicitly use the parameter constraint if you think it's ugly.
There is one other thing I thought of, which wouldn't be so frowned upon. Think about the Queryable.Cast<T> and Queryable.OfType<T> methods. They take a non generic IQueryable parameter but returns an IQueryable<T>. If you make sure to validate your assumptions about the parameter, it's probably clean enough. Then you would lose some compile-time type-safety though. You would need to have a non-generic base like BaseObjectWithDTO that BaseObjectWithDTO<TData,TKey> would inherit from. Your method would then look like:
public static IQueryable<D> ReturnDTO<D>(this IQueryable<BaseObjectWithDTO> query)
where D : BaseDTO, new()
{
if(query == null) throw new ArgumentNullException("query");
if( !typeof(BaseObjectWithDTO<D,int>) .IsAssignableFrom(query.GetType().GetGenericParameters()[0]))
throw new ArgumentOutOfRangeException("query");
//expression tree code to convert
}
That's not terrible. But it might not be good either. It's probably better than the other options I listed, but who knows.
Another syntax that might work for you just occurred to me, but it's also pretty abusive. Imagine you did go the BaseDTO<T> where T : BaseDTO<T>,new() route. You could declare the method on that type to extract the DTO queryable. This is what I'm thinking:
public abstract class BaseDTO<T>
where T : BaseDTO<T>, new()
{
public static T From(BaseObjectWithDTO<T,int> entity){
if(entity == null) throw new ArgumentNullException("entity");
//expression tree code to convert
}
}
then you don't really need that method ReturnDTO as an extension method anymore, because you have normal LINQ. You could still add it as syntactic sugar if you want, but using these semantics instead, your call ends up looking like:
IQueryable<ProductDTO> dtoQuery = from entity in Product.QuerySource select ProductDTO.From(entity);
which can also be written as
Product.QuerySource.Select(entity => ProductDTO.From(entity));
and if you were using an IEnumerable instead of an IQueryable could be
Product.QuerySource.Select(ProductDTO.From);
Please remember: All I'm saying is that you can do things this way. I'm not saying you should.

C# How to Initialize Generic class with object of type "Type"

I recently had this problem.
doSomething(typeof(int));
doSomething(typeof(MyClassA));
doSomething(typeof(MyClassB));
public void doSomething(Type _type)
{
var myGenObj = new MyGenericClass<_type>(); // Error. Really I'd want MyGenericClass<int>, MyGenericClass<MyClassA>, etc depending on what's passed in.
myGenObj.doSomeGenStuff();
// more stuff...
}
I think that this can be done with reflection somehow.. Possibly there's an easier way. I've been somewhat confused on how Type works vs Classes under the covers. Anyways thanks for any help.
Thanks.
You want Type.MakeGenericType and then Activator.CreateInstance... but then calling a method on the newly-created object will be tricky. Ideally you could have a non-generic base class or interface containing those members:
public interface IFoo
{
void CallSomeMethod();
}
public class MyGenericClass<T> : IFoo
{
...
}
// Names changed to be more conventional
public void DoSomething(Type type)
{
var genericType = typeof(MyGenericClass<>).MakeGenericType(type);
var instance = (IFoo) Activator.CreateInstance(genericType);
instance.CallSomeMethod();
}
If you do need to call a method which depends on the type parameter, you'll need to do that with reflection, or with dynamic which can streamline reflection-based code.
EDIT: As cdhowie says, if you always actually do know the type at compile-time, you can use a generic method which would make things much simpler. You'd then call the method like this:
DoSomething<int>();
DoSomething<MyClassA>();
DoSomething<MyClassB>();
Like this:
object myGenObj = Activator.CreateInstance(typeof(MyGenericClass<>).MakeGenericType(_type));
However, since the produced object is of a type that you don't know at compile-time, you can't really invoke members of the object through the generic type (except via reflection). If there is an ancestor type or implemented interface that you do know of at compile-time, you can cast to that and then invoke the member.
You might also consider wrapping this functionality in a generic method, which makes the whole thing easier to deal with:
public void doSomething<T>()
{
var myGenObj = new MyGenericClass<T>();
myGenObj.doSomeGenStuff();
}
If you have to support Type objects you can use an overload that cheats using reflection:
public void doSomething(Type _type)
{
this.GetType().GetMethod("doSomething", Type.EmptyTypes)
.MakeGenericMethod(_type)
.Invoke(this, null);
}

Creating an own Collection type of objects of type "Type" in C#

I am new to C# and i have the following problem:
I need to create a TypeCollection, that inherits from Collection and the type of objects in here are some types created by me.
In the InsertItem() overloaded method, i want to check if the object is from the specific type hierarchy that i created, else i throw an exception.
The code snippet is attached:
public class ObjectTypeCollection<Type> : Collection<Type>
{
protected override void InsertItem(int index, Type item)
{
if(!(Utility.IsFDTObject(item.GetType())))
{
throw new ArgumentException(string.Format("Type {0} is not valid", item.ToString()));
}
base.InsertItem(index, item);
}
}
The problem here is with the item instance. It doesnot have any method which allows me to get the currently passed Type. The GetType() doesnot return me the type that i have passed. Currently, i have used :
System.Type typ = System.Type.GetType(item.ToString());
to get the type and then passed this to the Utility method. This works fine. Is this the right approach?
Could you please help me here?
You can set a constraint on type parameter Type, see here: http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx
This is statically checked and you don't need to do anything dynamic like you're currently doing. Specifically:
public class ObjectTypeCollection<T> : Collection<T> where T : <base class name>
Use Type.IsAssignableFrom method:
public class FDTObject {}
public class MyDTObject1 : FDTObject {}
public class MyDTObject2 : FDTObject { }
public class ObjectTypeCollection : Collection<Type>
{
protected override void InsertItem(int index, Type item)
{
if (!typeof(FDTObject).IsAssignableFrom(item))
{
throw new ArgumentException(string.Format("Type {0} is not valid", item));
}
base.InsertItem(index, item);
}
}
Usage:
var collection = new ObjectTypeCollection();
collection.Add(typeof(MyDTObject1)); // ok
collection.Add(typeof(MyDTObject2)); // ok
collection.Add(typeof(String)); // throws an exception
Unless I am missunderstanding what you want, can't you just use the generic list?
You can initialize the list with the type parameter set to your base class:
var list = new List<FDTObject>(); // assuming this is one of your base classes based upon your example.
you can then add any object to the list that is an FDTObject or inherits from FDTObject
You can use Type.IsAssignableFrom to check if an instance of a Type is assignable from an instance of another Type (if they are compatible). Like this:
if (typeof(FDTObject).IsAssignableFrom(item))
But your question is a bit unclear. Maybe you don't want to insert actual types but rather objects of a specific type and be able to instantiate the Collection with different types? Then you could constrain the generic parameter in your class:
public class ObjectTypeCollection<T> : Collection<T> where T: FDTObject
Or you just want a collection where all objects are an FDTObject or descendants of it. Then you could just use a List<FDTObject> and you have instant static type checking (the best solution if that is what you itended):
List<FDTObject> fdtList = new List<FDTObject>();
For me, it's still quite unclear though. Do you want to add instances of System.Type to the collection (then you would need to remove the first generic argument directly after the class name)? Or did you just happen to choose Type as the name for your generic parameter (which is a bad choice since there's already a type, namely System.Type named like that)?

How to convert a type to a generic version given its type?

I'm having a spot of trouble with generics in C#. I have to store a number of generic objects together but their type parameter differs so I have made a non-generic interface which they implement. What I'm looking for is a way to convert back to the generic version, given a type object. I know I can do it with reflection but I was wondering if there was a better/more elegant solution.
The following code illustrates the problem:
interface ITable
{
public Type Type { get; }
}
class Table<T> : ITable
{
public Type Type { get{ return typeof(T); } }
}
class Program
{
static void Main(string[] args)
{
var tables = new Dictionary<string, ITable>();
... //insert tables
DoStuffWithTable(tables["my table"]); //This doesn't work
}
public static void DoStuffWithTable<T>(Table<T> table)
{
...//Some work
}
}
Is there a clean way for me to invoke the generic DoStuffWithTable method based on the instance of the Type object I can get from its interface method?
If you are starting from a non-generic type (ITable), then the only way to do this is via reflection (MakeGenericMethod). It isn't very pretty or especially fast, but it works...
public static void DoStuffWithUntypedTable(ITable table)
{
typeof(Program).GetMethod("DoStuffWithTable")
.MakeGenericMethod(table.Type)
.Invoke(null, new object[] { table });
}
As an aside - note that there is a bit of risk in assuming that an ITable is actually a Table<T> - you should probably verify that, and maybe also use an interface (ITable<T>).
Edit: if it really must be a Table<T>, then you can enforce this (including subclass support, such as FooTable : Table<Foo> as:
public static void DoStuffWithUntypedTable(object table)
{
Type type = table.GetType();
while (type != typeof(object))
{
if (type.IsGenericType && type.GetGenericTypeDefinition()
== typeof(Table<>))
{
typeof(Program).GetMethod("DoStuffWithTable")
.MakeGenericMethod(type.GetGenericArguments()[0])
.Invoke(null, new object[] { table });
return;
}
type = type.BaseType;
}
throw new ArgumentException("Not a Table<T> or subclass");
}
The problem is that you don't know the type at compile-time - which is what generics is tailored for.
To call a generic method where you only know the type argument at execution time, you basically need reflection - get the generic method, call MakeGenericMethod and then invoke the returned method.
You need to cast, you actually need to know the actual type, unless it doesn't make sense.
DoStuffWithTable<MyType>((Table<MyType>)tables["my table"]);
You should consider to make the method not generic if you want to call it without knowing the actual type.
There is a misunderstanding here between generics and polymorphism. Generally, generics deal with things of a single type where the type is defined at compile time*, whereas polymorphism is about things of different types that exhibit common functionality defined as an interface or base type.
You seem to be trying to create a polymorphic type (things of different type that exhibit the same behaviour) where each polymorphic instance is defined by a generic type.
So, to update your code:
interface ITable
{
void SomeCommonFunction ();
}
class Table<T> : ITable
{
void SomeCommonFunction () { do something - T is known at compile time! }
}
class Program
{
static void Main(string[] args)
{
var tables = new Dictionary<string, ITable>();
... //insert tables
tables["my table"].SomeCommonFunction ();
}
}
Now, if you want to do different things in SomeCommonFunction that is dependant on the type T, then you want to have specific instantiations of the Table type. C# doesn't allow for specialisations of generic type in the way that C++ can with its templates so you'll have to do:
class TableOfInt : ITable
{
void SomeCommonFunction () { do something different! }
}
* You can define the type at run time in C# but that's getting into crazy reflection territory.

Why does this generic method require T to have a public, parameterless constructor?

public void Getrecords(ref IList iList,T dataItem)
{
iList = Populate.GetList<dataItem>() // GetListis defined as GetList<T>
}
dataItem can be my order object or user object which will be decided at run time.The above does not work as it gives me this error
The type 'T' must have a public parameterless constructor in order to use it as parameter 'T' in the generic type
public void GetRecords<T>(ref IList<T> iList, T dataitem)
{
}
What more are you looking for?
To Revised question:
iList = Populate.GetList<dataItem>()
"dataitem" is a variable. You want to specify a type there:
iList = Populate.GetList<T>()
The type 'T' must have a public
parameterless constructor in order to
use it as parameter 'T' in the generic
type GetList:new()
This is saying that when you defined Populate.GetList(), you declared it like this:
IList<T> GetList<T>() where T: new()
{...}
That tells the compiler that GetList can only use types that have a public parameterless constructor. You use T to create a GetList method in GetRecords (T refers to different types here), you have to put the same limitation on it:
public void GetRecords<T>(ref IList<T> iList, T dataitem) where T: new()
{
iList = Populate.GetList<T>();
}
Your revised question passes in dataItem as an object of type T and then tries to use it as a type argument to GetList(). Perhaps you pass dataItem in only as a way to specify T?
If so, the you may want something like so:
public IList<T> GetRecords<T>() {
return Populate.GetList<T>();
}
Then you call that like so:
IList<int> result = GetRecords<int>();
The issue with demanding a public, parameterless constructor can only be because Populate.GetList demands it - i.e. has the "T : new()" constraint. To fix this, simply add the same constraint to your method.
Actually, I doubt that ref is a good strategy here. At a push, out might do (since you don't read the value), but a far simpler (and more expected) option is a return value:
public IList<T> GetRecords<T>(T dataItem) where T : new()
{ // MG: what does dataItem do here???
return Populate.GetList<T>();
}
Of course, at that point, the caller might as well just call Populate.GetList directly!
I suspect you can remove dataItem too... but it isn't entirely clear from the question.
If you don't intend it to be generic (and dataItem is the template object), then you can do this via MakeGenericMethod:
public static IList GetRecords(object dataItem)
{
Type type = dataItem.GetType();
return (IList) typeof(Populate).GetMethod("GetList")
.MakeGenericMethod(type).Invoke(null,null);
}
You can use Generic with < T > that will accept the type in runtime like you want.
Getrecords<T> ...
This should have any more detailed information that you need.
http://msdn.microsoft.com/en-us/library/twcad0zb(VS.80).aspx

Categories

Resources