Has it a more "beautiful" solution for a generic determination? - c#

I have the following code which works but I think it may not beoptimal because in theory compiler can determinate a generic type from the calling child class. Is there a way to rewrite this code such that I do not need to provide the ChildType generic type parameter?
public abstract class Test<ChildType, T> where ChildType: Test<ChildType, T>, new()
{
public T Field { get; set; }
public static ChildType Get(T field) {
return new ChildType() { Field = field };
}
}
public class ChildTest: Test<ChildTest, string>
{
}
// Call sample
var child = ChildTest.Get("test");

The answer is that it is pretty much required for the Test class to have the ChildType generic type specified. You could use reflection to get the current type and instantiate an instance of it but reflection is generally best avoided.
To see why consider the Test class on its own and in particular this line:
return new ChildType() { Field = field };
That line requires two pieces of information. First it needs to know what the actual type of ChildType is. You can't hardcode it because it can of course vary. The second piece of information it needs is to know it can create a new object of this type in this way.
Both of these pieces of information are provided through the generic type parameter and the generic constraint which is why it is required.

Related

How to cast value returned by Invoke to IEnumerable<type> where type is some variable of type T?

I have the situation, where I want to call some generic method on another object and get IEnumerable result.
private void SomeFunction(Type type)
{
var method = context.GetType()
.GetMethods()
.FirstOrDefault(_ => _.Name == "GetStorage" && _.IsGenericMethod);
var storage = getStorage.MakeGenericMethod(type)
.Invoke(context, new object[] {})
.AsEnumerable();
//Some magic needed here. Something like Cast<type>,
//but type - variable
//More code ...
}
Could anyone suggest me how to figure out this situation. Thank you.
I have already seen this and similar questions:
Casting Results from Generic Method Invocation?
But they doesn't answer on my question, how to do same, when I don't know type, to which I want to cast, and type is stored as variable.
I can't makeSomeFunction a generic method, because the real situation is that I am iterating some list with System.Type and calling lambda (i. e. SomeFunction) on each element
There are some things you need to do to get what you want. You say you want to have a lambda, but that means that you need to define that lambda, which is on a type you do not know yet. You can redesign your lambda into an interface.
Also, I find it much easier to define a generic class that does exactly what I want. By creating an instance of this class through reflection, and only there, I can implement the rest of the class in a strong typed way. This takes away the 'not knowing what type I have' in most places.
Like this. First, the executor interface:
public interface ISomeFunctionExecutor
{
void Execute(SomeContext context);
}
Then the interface that I need to implement on the entities, which is the lambda so to speak.
public interface IEntityWithSomeFunction
{
void SomeFunction();
}
Now the implementation of the executor.
public class SomeFunctionExecutor<TType> : ISomeFunctionExecutor
{
public void Execute(SomeContext context)
{
var data = context.GetStorage<TType>().Cast<IEntityWithSomeFunction>();
foreach (var item in data)
{
item.SomeFunction();
}
}
}
And finally, the usage of it all:
// Usage:
SomeContext context = new SomeContext();
Type type = typeof(SomeEntity);
var executorType = typeof(SomeFunctionExecutor<>).MakeGenericType(type);
var executor = Activator.CreateInstance(executorType) as ISomeFunctionExecutor;
if (executor != null)
{
executor.Execute(context);
}
Basically the point is: define a generic class to do what you need to do where you do know the type, and create an instance of this class using reflection. It makes it much easier than having a whole method where you do not know the type.

Dynamically pass class and method names to a method using generics

I want to pass in dynamically a class name and a method name to a method and keep this dynamic, I'm understanding that I should use generics and possible constraints.
Example, I have a class
MemberRequestDTO (contains several properties)
I also that a Method called
RecordsToRetrieve
Using some reflection I was wanting to dynamically get the values of the properties, which I figured out how to do that, but then I realized that is is too hard code and tightly coupled of which I figured time to refactor and create a method with a signature that uses generics with constraints. having trouble with understand the use of and the constraints etc..
So I want to pass in a class name and be able to use it in the method, with reflection I plan to use it like:
Type type = typeof(classname);
I started reading and researching and I start playing with code like this:
public void GetTypeValues<T>() where T : class , new()
How do I pass in the class name of MemberRequestDTO?
What does the Generic new for me?
How do I pass a class name into the parens ()?
If I use does it also get pass into parens?
How can I pass in class and method?
Reading the above "Where T has the constraints (enforced) to be of type "class AND new() ?
A little lost and confused on this, forgive me.
EDIT:
Based on the answers and some research, I'm understanding this a bit more:
Lets forget about me trying to pass in a method, say I just want to pass in a class
Say the class with properties looks like this
public class MemberRequestDTO
{
public DateTime DateRequested { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I will New this up
var memberRequestDTO = new MemberRequestDTO();
Then I want to pass this to class into a method that is generic
How do I go about passing an instance of a object into a generic method? What about the signature , example public void GetTypeValues() where T : class , new()
Would I want to have the contraints of class and new() ?
For the above, is T the instance of the class? Thus the purpose is that I can be
Saying
GetTypeValues(memberRequestDTO)
( this is my actual question , pass into whatever class I instantiated and that let the method "handle" dealing with that class with looping through the properties and getting me the name values of the properties dynamically and yes it probably will not remain a void method )
Should passing in memberRequestDTO be with quotes or without? I want to be able to pass in any instance of a class to the member to then manipulate it more. () should T be there ? should the parens () be empty or contain an generic parameter for the class object ?
Here are your answers:
GetTypeValues<MemberRequestDTO>()
new() is a constraint for the Type Parameter - T. It says that the type argument T must have a public parameterless constructor. In your case, MemberRequestDTO class must a public parameterless constructor like below:
public class MemberRequestDTO
{
public MemberRequestDTO() { ... }
}
As a class name is of reference type, you can pass it as a type into the parens like: SomeMethod(typeof(MemberRequestDTO)); where the signature of the method be void SomeMethod(Type type) { }
If you pass the class as a type parameter as in point (1), it does not get passed into the parens()
class constraint implies that "The type argument must be a reference type; this applies also to any class, interface, delegate, or array type."
and new() constraint implies that "The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last."
EDIT:
If I catch your point, then the generic method definition would be something like:
public void GetTypeValues<T>(T typeObject) where T : class
{
// typeObject specific operations
}
That uses typeObject dynamically, getting the "execution-time compiler" to perform type inference to work out T. See the reference here. Moreover, imho, you don't need the new () constraint on T here.
After that, you can pass an instance of any class to this method like below:
var memberRequestDTO = new MemberRequestDTO();
GetTypeValues((dynamic) memberRequestDTO);
EDIT 2:
USAGE: Get Type Values dynamically using Reflection
This method returns the property values wrapping into IEnumerable<KeyValuePair<string, object>>.
public static IEnumerable<KeyValuePair<string, object>> GetTypeValues<T>(T typeObject) where T : class
{
// typeObject specific operations
IEnumerable<KeyValuePair<string, object>> typeValues =
typeObject
.GetType()
.GetProperties()
.Select(property => new KeyValuePair<string, object>(property.Name, property.GetValue(typeObject)));
return typeValues;
}
How do I pass in the class name of MemberRequestDTO ?
You already have one. In a generic method "Type parameter" in this case T will be the name of type you're interested in.
public void GetTypeValues<T>() where T : class , new()
{
string typeName = typeof(T).Name;
}
What does the Generic new for me?
It is a contraint which will prevent you to pass any type without public parameterless constructor. In other words it will allow you to new up type passed in as "Type parameter"
public void GetTypeValues<T>() where T : class , new()
{
T instance = new T();//This is not possible without new constraint
}
How do I pass a class name into the parens () ?
If I use does it also get pass into parens?
Not sure what is that parens() Need more info to answer this.
How can I pass in class and method?
If I understand correctly "Type parameter" T is the runtime type which you use. So you get a Type there. Am not sure about what you mean by class? Class cannot be passed only instances can be passed.
For methods there are number of ways. You can pass MethodInfo or method name or A delegate, or a MethodCallExpression etc.
Reading the above "Where T has the constraints (enforced) to be of
type "class AND new() ?
Yes. class constraint prevents you from passing value types, new() constraint allows you to new up things.
Read more about generics here and here
I'm a little confused about what you want to do but I'll give it a shot. I can see two possible interpretations and they differ on what the caller is starting with and what you're trying to achieve.
Interpretation #1: The caller starts out knowing the name of the class and the name of the method it wants to invoke later, using an object it has in hand. This can be achieved as follows:
public Func<object, object> RecordMethod(string typeName, string methodName)
{
var type = Type.GetType(typeName);
var method = type.GetMethod(methodName);
return (object o) => method.Invoke(o, new object[0]);
}
var method = RecordMethod("MemberRequestDTO", "RecordsToRetrieve");
// later that day ...
MemberRequestDTO someObj = ...;
var result = method.Invoke(someObj);
This is fine if you need to work with type names and method names dynamically, e.g. from user input. Note that this approach requires the use of object throughout, and will only work with a method that takes no parameters. Also note that in this way the type cannot be guaranteed to have a no-arg constructor, so the caller must provide the object himself.
Interpretation #2: The caller starts out knowing the actual class and the actual method it wants to invoke later, using an object that can be constructed later. This can be achieved as follows:
public Func<TOutput> CaptureMethod<TInput, TOutput>(Func<TInput, TOutput> method)
where TInput : new()
{
return () =>
{
var source = new TInput();
return method(source);
};
}
var capturedMethod = (MemberRequestDTO dto) => dto.RecordsToRetrieve();
// later that day ...
var result = capturedMethod();
This captures a known method and returns a function which, when invoked, will instantiate your class and call the method on it. This is a more static approach (the caller knows more than in the previous example) and is able to enforce a constraint that the type being worked with must have a no-arg constructor.
I don't know if I've answered your question but this should at least give you some ideas.

Adding generic constraints at runtime?

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.

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.

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.

Categories

Resources