Imagine the Func Func<Arguments, bool?>, where Arguments is an abstract class. Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. Of course the type of Arguments is important for validation before the Func is called. Is there a way to get the type of Arguments?
e.g.:
public bool? test(Arguments arg) {
Func test = Func<SomeArguments, bool?>;
Type argType = GetFirstArgumentType(test); // gives SomeArguments.GetType();
if (arg.GetType() == argType) {
return test(new SomeArguments());
}
return null;
}
You can use Type.GetGenericArguments to get the System.Type of the first generic argument to your Func<T,bool?>.
That being said, it would likely be easier to store a Dictionary<Type, Delegate> to hold your types, and just do a direct lookup instead.
Based on your description, " Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. " I might suggest that you use a parameter constraint:
public bool? test<T>(T arg) where T :Arguments, new()
{
var type = typeof(T);
// ...
}
This will get you the type checking you describe.
Related
I like to send a generic type converter function to a method but I can't figure out how to do it.
Here's invalid syntax that explains what I like to achieve, the problem is I don't know how to specify the generic type together with my func:
public void SomeUtility(Func<T><object,T> converter)
{
var myType = converter<MyType>("foo");
}
Edit (see also my discussion in the comments with Lawrence) : By "generic type converter" I meant I would like to pass in a converter that can convert to any strong type <T> (not object), so the next line in my method could be:
var myOtherType = converter<MyOtherType>("foo");
The delegate I like to pass as a parameter would look something like this:
private delegate TOutput myConverterDelegate<TOutput>(object objectToConvert);
This is more a syntax / C# exploration now, to get things done I will probably use an interface instead, but I do hope this is possible to accomplish with a func/delegate.
You cannot have instances of generic functions or actions - all type parameters are defined upfront and cannot be redefined by the caller.
An easy way would be to avoid polymorphism altogether by relying on down-casting:
public void SomeUtility(Func<Type, object, object> converter)
{
var myType = (MyType)converter(typeof(MyType), "foo");
}
If you want type safety, you need to defer the definition of the type parameters to the caller. You can do this by composing a generic method within an interface:
public void SomeUtility(IConverter converter)
{
var myType = converter.Convert<MyType>("foo");
}
interface IConverter
{
T Convert<T>(object obj);
}
Edit:
If the 'converter type' is known at the call-site, and only this type will be used inside the utility method, then you can define a generic type on the method and use that, just like other posters have suggested.
public void SomeUtility<T>(Func<object, T> converter)
{
var myType = converter("foo");
}
and then:
SomeUtility(arg => new MyType());
The generic type inference will work in this case.
You need to make SomeUtility generic as well. Doing this and fixing the syntax gives:
public void SomeUtility<T>(Func<object,T> converter)
{
var myType = converter("foo");
}
You have to know the T type at compile-time to use it. The T can either be specified at class-level or at method-level.
class SomeClass<T> {
public void SomeUtility(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
}
or
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
Is possible set method return type, like type to generic class ?
I have Generic Class:
class Generic<T>
{
public static DataSet test(T input)
{
//Some logic...
}
}
Another Class, where i call my generic class.
It works for this examples:
Generic<int>.test(10);
But if i want to call different methods, with complex unknown date types, i don't know how i put their date type like Generic Type.
For Example
var data = Data.GetData(); // return List<string,int>
var data2 = Data.GetData2() // return Tuple<List<string>, List<int>>
I try use method GetType, for get returns method type, something like this, but it doesn't work.
Generic<data.GetType()>.test(data);
Is it possible, something like this ?
No, you can't specify the generic type at runtime without reflection, but there may be other ways to solve your problem. You could put the generic constraint on the method instead of the class:
class Generic
{
public static dynamic Test<T>(T input)
{
//Some logic...
}
}
which then can be inferred from the input type:
Generic.Test(data);
Return Type of a function is known in compile time.
Therefore if I understood your question correctly what you're asking for isn't possible. TL;DR You can't set return type in runtime.
I like to send a generic type converter function to a method but I can't figure out how to do it.
Here's invalid syntax that explains what I like to achieve, the problem is I don't know how to specify the generic type together with my func:
public void SomeUtility(Func<T><object,T> converter)
{
var myType = converter<MyType>("foo");
}
Edit (see also my discussion in the comments with Lawrence) : By "generic type converter" I meant I would like to pass in a converter that can convert to any strong type <T> (not object), so the next line in my method could be:
var myOtherType = converter<MyOtherType>("foo");
The delegate I like to pass as a parameter would look something like this:
private delegate TOutput myConverterDelegate<TOutput>(object objectToConvert);
This is more a syntax / C# exploration now, to get things done I will probably use an interface instead, but I do hope this is possible to accomplish with a func/delegate.
You cannot have instances of generic functions or actions - all type parameters are defined upfront and cannot be redefined by the caller.
An easy way would be to avoid polymorphism altogether by relying on down-casting:
public void SomeUtility(Func<Type, object, object> converter)
{
var myType = (MyType)converter(typeof(MyType), "foo");
}
If you want type safety, you need to defer the definition of the type parameters to the caller. You can do this by composing a generic method within an interface:
public void SomeUtility(IConverter converter)
{
var myType = converter.Convert<MyType>("foo");
}
interface IConverter
{
T Convert<T>(object obj);
}
Edit:
If the 'converter type' is known at the call-site, and only this type will be used inside the utility method, then you can define a generic type on the method and use that, just like other posters have suggested.
public void SomeUtility<T>(Func<object, T> converter)
{
var myType = converter("foo");
}
and then:
SomeUtility(arg => new MyType());
The generic type inference will work in this case.
You need to make SomeUtility generic as well. Doing this and fixing the syntax gives:
public void SomeUtility<T>(Func<object,T> converter)
{
var myType = converter("foo");
}
You have to know the T type at compile-time to use it. The T can either be specified at class-level or at method-level.
class SomeClass<T> {
public void SomeUtility(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
}
or
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
(Thanks everyone for the answers, here is my refactored example, in turn another StackOverflow question about the Single Responsibility Principle.)
Coming from PHP to C#, this syntax was intimidating:
container.RegisterType<Customer>("customer1");
until I realized it expresses the same thing as:
container.RegisterType(typeof(Customer), "customer1");
as I demonstrate in the code below.
So is there some reason why generics is used here (e.g. throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, i.e. you don't need the typeof() when sending the type?
using System;
namespace TestGenericParameter
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
container.RegisterType<Customer>("test");
container.RegisterType(typeof(Customer), "test");
Console.ReadLine();
}
}
public class Container
{
public void RegisterType<T>(string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
}
public void RegisterType(Type T, string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
}
}
public class Customer {}
}
//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method.
That means, you can write methods like
public T GetAs<T>(string name)
where the return type can be checked by the compiler and boxing value types can sometimes be avoided.
The caller would write:
int value = GetAs<int>("foo");
Whithout generics, you would have to write
public object GetAs(Type t, string name)
and the caller has to cast the result again:
int value = (int)GetAs(typeof(int), "foo");
A primary reason is the type safety at compile time. If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.
This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.
public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}
This code will only work if TConcrete is implementing or inheriting TAbstract. If this method took two Type parameters, your method should validate this relationship.
A simple answer is type inference where possible.
If the generic type is used in the method signature, you can omit it because the type could be inferred:
void SomeMethod<T>(T x, T y) where T : IComparable<T> {
Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}
So the usage is simplified:
SomeMethod(3, 4); // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");
If the generic type parameter is not used in the method signature the type inference is not possible:
var emptySequence = Enumerable.Empty<int>();
I think one of the primary uses is type safety with arguments and return values. In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).
A more appropriate use might be:
public T RegisterType<T>(string name)
{
T obj = new T();
obj.DoSomething();
return obj;
}
or maybe
public void DoSomething<T>(T obj)
{
//operate on obj
}
If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.
For one example, compare the code needed to create an instance of your type using the typeof option versus a generic. Or return an instance of the type. Or accept an instance of the type as an argument. Or set a property on an instance of the type.
In general, if you will be working only with the type itself you can accept a type parameter. If you want to do anything with an instance of the type, use a generic.
Another reason to use a generic is if you want to apply constraints to the type. For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above. The compiler will enforce this so you can't build code that doesn't comply with your requirements.
I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor). Using "typeof" will let you send anything through.
I have a marker interface defined as
public interface IExtender<T>
{
}
I have a class that implements IExtender
public class UserExtender : IExtender<User>
At runtime I recieve the UserExtender type as a parameter to my evaluating method
public Type Evaluate(Type type) // type == typeof(UserExtender)
How do I make my Evaluate method return
typeof(User)
based on the runtime evaluation. I am sure reflection is involved but I can't seem to crack it.
(I was unsure how to word this question. I hope it is clear enough.)
I went this way based on some of the tidbits provided. It could be made more robust to handle multiple generic arguments on the interface.... but I didn't need it to ;)
private static Type SafeGetSingleGenericParameter(Type type, Type interfaceType)
{
if (!interfaceType.IsGenericType || interfaceType.GetGenericArguments().Count() != 1)
return type;
foreach (Type baseInterface in type.GetInterfaces())
{
if (baseInterface.IsGenericType &&
baseInterface.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition())
{
return baseInterface.GetGenericArguments().Single();
}
}
return type;
}
There is an example of doing what you describe in the MSDN documentation for the GetGenericTypeDefinition method. It uses the GetGenericArguments method.
Type[] typeArguments = t.GetGenericArguments();
Console.WriteLine("\tList type arguments ({0}):", typeArguments.Length);
foreach (Type tParam in typeArguments)
{
Console.WriteLine("\t\t{0}", tParam);
}
In your example I think you would want to replace t with this. If that doesn't work directly you may need to do something with the GetInterfaces method to enumerate the current interfaces on your type and then GetGenericArguments() from the interface type.
I read your question completely differently than the other answers.
If the evaluate signature can be changed to:
public Type Evaluate<T>(IExtender<T> it)
{
return typeof(T);
}
This doesn't require the calling code to change, but does require the parameter to be of type IExtender<T>, however you can easily get at the type T :
// ** compiled and tested
UserExtender ue = new UserExtender();
Type t = Evaluate(ue);
Certainly it's not as generic as something just taking a Type parameter, but this is a different take on the problem. Also note that there are Security Considerations for Reflection [msdn]