This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 8 years ago.
Suppose I have an unconstrained generic method that works on all types supporting equality. It performs pairwise equality checks and so works in O(n2):
public static int CountDuplicates<T>(IList<T> list)
{
/* ... */
}
I also have a constrained generic method that only works with types supporting sorting. It starts from sorting the list in O(n log n), and then counts all duplicates in one pass:
public static int CountDuplicatesFast<T>(IList<T> list)
where T : IComparable<T>
{
/* ... */
}
So, a caller can choose to invoke the fast method if it is statically known that the type of elements of the list supports ordering. It might happen that the caller itself works with generic IList<T> where T is unconstrained, so its only option to invoke the first (slow) method.
Now, I want the first method to check at runtime if the type T actually implements the interface IComparable<T> and if so, invoke the fast method:
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast(list);
}
else
{
/* use the slow algorithm */
}
}
The problem is the compiler rejects the invocation CountDuplicatesFast(list):
error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Program.CountDuplicatesFast<T>(System.Collections.Generic.IList<T>)'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IComparable<T>'.
Is it possible to persuade the compiler to trust me that I know what I am doing, and to skip the constraint check?
You can use a helper class and dynamic type to skip compile-time checks:
sealed class CountDuplicatesFastCaller
{
public int Call<T>(IList<T> list) where T : IComparable<T>
{
return CountDuplicatesFast(list);
}
}
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof (IComparable<T>).IsAssignableFrom(typeof (T)))
{
return ((dynamic) new CountDuplicatesFastCaller()).Call(list);
}
else
{
/* use the slow algorithm */
}
}
This should be faster than pure reflection because of DLR caching mechanisms.
Here's a way to do it using dynamic:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast((dynamic)list);
}
Or with reflection:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
var method = typeof(MyType).GetMethod("CountDuplicatesFast");
var generic = method.MakeGenericMethod(typeof(T));
return (int)generic.Invoke(null, new object[] { list });
}
I don't think that there's a way to do this statically (i.e. without reflection or dynamic).
Related
I have overloaded generic methods that look like this:
public static T DoSomething<T>(T val)
{
return val;
}
public static IEnumerable<T> DoSomething<T>(IEnumerable<T> vals)
{
return vals.Select(x => DoSomething(x));
}
The problem I am running into is that the following code won't compile:
var myList = new List<SomeObject>();
// This will not compile
PropertyOfTypeIEnumerable_SomeObject = MyStaticClass.DoSomething(myList);
The compiler is complaining that it can't convert SomeObject into IEnumerable<SomeObject>. This indicates that the compiler is choosing the first version of DoSomething, which takes generic type T, as opposed to the second version, which takes the more restrictive generic type IEnumerable.
I can confirm this is the case by renaming the second overloaded method to DoSomethingList and calling that name explicitly:
public static T DoSomething<T>(T val)
{
return val;
}
public static IEnumerable<T> DoSomethingList<T>(IEnumerable<T> vals)
{
return vals.Select(x => DoSomething(x));
}
// ...
var myList = new List<SomeObject>();
// This compiles ok
PropertyOfTypeIEnumerable_SomeObject = MyStaticClass.DoSomethingList(myList);
My question is, why doesn't the compiler choose the most restrictive matching generic implementation to call, and is there any way I can get that behavior without having to name it uniquely and call it explicitly? If the example were calling overloads for different objects which inherited from one another, then it would choose the most restrictive overload based on the declared variable type. Why doesn't it do this for generics as well?
Another option would be to not overload the methods, but to check inside of the DoSomething method to see if T is assignable from IEnumerable<>, but then I don't know how to actually cast it to something I could call the Linq method on, and I don't know how to get the compiler to be ok with returning the result of that Linq method, since I will know that the return result needs to be IEnumerable, but the compiler will not.
Generics in C# differ in many ways from C++ templates (1). You'd be right that it would call the more restrictive IEnumerable<T> function if we were working in C++ meta-programming. However, in C# the <T> function matches List<T> better, because it is more exact.
I tested your code above and it compiles just fine for me on .NET v4.0.30319 but it returns a List<T> type instead of the expected reduced IEnumerable<T> type that a Select call returns. Indicating that the <T> function was called.
If you want to perform DoSomething on all objects in IEnumerable extended classes, then here is a way to do so:
public static T DoSomething<T>(T val)
{
switch (val)
{
case IEnumerable vals:
foreach (object x in vals)
DoSomething(x);
break;
}
return val;
}
I've set it up in a way that allows for matching other specific types, as I'd guess that each different type is going to do something different. If that is not intended you can always use just a simple if...is statement matching.
This question already has answers here:
Why doesn't C# infer my generic types?
(9 answers)
Closed 7 years ago.
Consider the following function:
public void DoSomething<TSource>(TSource data)
{
// ...
}
In C#, the compiler may implicitly infer TSource's type by inspecting the method's argument:
DoSomething("Hello") // Works fine. DoSomething<string>("Hello") is called.
Why can't we do the same when there is a generic return value?
For instance:
public TResult DoSomething<TResult, TSource>(TSource data)
{
// ...
}
TResult cannot be inferred (and I understand why), but the compiler can surely infer TSource's type, can't it?.
However, this does not compile:
int result = DoSomething<int>("Hello"); // This should call DoSomething<int,string>("Hello")
It's not a matter of compiler - it's that C# requires that you either explicitly specify all the type arguments or let it infer all of them.
There is no middle ground using the syntax you've attempted, and I imagine it's because if you had a generic method like this:
public void DoSomething<T1, T2>(T1 data, T2 data)
{
// ...
}
And you used it like this:
var obj1 = "Hello!";
var obj2 = "Hello?";
DoSomething<IEnumerable<char>>(obj1, obj2);
The last line could be shorthand for two equally valid things:
DoSomething<string, IEnumerable<char>>(obj1, obj2);
DoSomething<IEnumerable<char>, string>(obj1, obj2);
A different syntax (like <string, ?>) or additional inference rules would have to be put in place to make cases like this meaningful and non-ambiguous. I imagine the design team thought that it wasn't worth it.
Note that if you really want partial generic type inference, there is a common pattern of splitting the call into two calls, with a helper object to hold the information between the calls. This is essentially currying, applied to type parameters.
I'll present the pattern in a form that uses a public interface and an private implementation but if you're not concerned about that, you can skip the interface altogether.
public TResult DoSomething<TResult, TSource>(TSource data)
{
// ...
}
Would become:
public IWrapper<TSource> DoSomething<TSource>(TSource data)
{
return new WrapperImplementation<TSource>(data);
}
Where:
public interface IWrapper<T>
{
TResult Apply<TResult>();
}
class WrapperImplementation<T> : IWrapper<T>
{
private readonly T _source;
public WrapperImplementation(T source)
{
_source = source;
}
public TResult Apply<TResult>()
{
// ...
}
}
The usage is:
DoSomething("Hello").Apply<int>();
I came across this problematic quite often: I like to overload some method with same parameters for different return types, but .NET refuses generic constraints to sealed classes/primitives. I'll refer to this pattern as phantom generics.
I know an ugly workaround: Putting every single interface the type implements behind the where statement.
My Question: Is there any way to use explicit types in generics to illustrate the return type and keep methods distinct?
Here is my code:
public static class Reinterpret {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value); //reinterpret the bytes of 'value' to a float
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
}
Here's one slightly different way of approach it:
// Constraints just to be vaguely reasonable.
public static class Reinterpret<T> where T : struct, IComparable<T>
{
public T Cast(int value) { ... }
public T Cast(uint value) { ... }
public T Cast(float value) { ... }
public T Cast(double value) { ... }
// etc
}
For the implementation, you could just have a Func<int, T> field, a Func<double, T> field etc, and then have a big static constructor:
static Reinterpret()
{
if (typeof(T) == typeof(int))
{
// Assign all the fields using lambda expressions for ints.
// The actual assignment might be tricky, however - you may
// need to resort to some ghastly casting, e.g.
castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
x => *((double*)&value;
}
....
}
Then for any type you didn't want to support, the fields would be null. Each Cast method would look like:
if (castIntMethod != null)
{
return castInt(value);
}
throw new InvalidOperationException("...");
To be honest, this isn't something I'd really want to do. I'd generally just use BitConverter. But it's an option.
Generics are not templates. They do not act like templates. They cannot be made to act like templates.
A "phantom" generic parameter is not going to help you simulate templates (and reinterpret_cast is not an actual template, anyway), because you soon are going to run into the fact that generics do not support specialization.
In particular, you asked "Is there any way to use explicit types in generics to ... keep methods distinct?" and commented that "the generic constraints ... keeps [sic] the methods distinct". But they actually do not. These methods are distinct only because the argument types are different. Generics are computed from overloads, they do not influence overloading.
TL;DR: (the title gives it away) Can I "Implicitly drop the generic argument from List<T>" in one single conversion?
A friend asked me today if it would be possible to implicitly convert a List<T> to a non-generic wrapper.
var list = new List<_some_type_>();
ObjectResult result = list;
The method would look something like this:
public static implicit operator ObjectResult(List<T> list) { ... }
Clearly, the T here is not defined, and the implicit operator's method name is the type name, ergo you can't include a generic parameter to the method name unless the type were actually generic, i.e.:
class ObjectResult<T> { ... }
Instead of
class ObjectResult { ... }
The constraints we have with user-defined conversions are (am I missing any?):
Cannot convert to or from a Base type
Cannot convert to or from an interface.
Must make conversion enclosed in one of the two types.
What makes List<T> so hard:
List<T>'s only derivation comes from Object; thus we'd have to convert directly from List<T>
List<T> has only interfaces, again, must be directly from List<T>
List<T>, obviously, is compiled up in the framework, so, it must be from our wrapper
I thought of a 2-step solution where there is a middle man we can convert from (whereas the only middle man with List<T> is Object, and due to rule #1, that's not an option).
public class ObjectResult
{
public static implicit operator ObjectResult(WrapperBase arg) { ... }
}
public class WrapperBase { }
public class ObjectResultWrapper<T> : WrapperBase
{
public static implicit operator ObjectResultWrapper<T>(List<T> arg) { ... }
}
Then, the invoking code would look like this:
var list = new List<int>();
ObjectResultWrapper<int> wrap = list;
ObjectResult result = wrap;
This doesn't solve the problem really, it's only a work around to drop T implicitly (but in two steps, not one). At this point, it'd be easier to have a helper method, and not use user-defined conversions.
There may be arguments against the goal of implicitly dropping the generic argument - I don't have anything else of why he feels this was important. Consider this simply an academic question.
The answer: No, You can't do that with an implicit cast.
Alternatives:
I think the best thing would be a static ObjectWrapper.FromList<T>(List<T>) method.
The wrapper cast is an option as well, though not nearly as elegant.
How about declaring a static "Convert" function instead of trying to declare a conversion operator? Then you could use the compiler's type inference do something like this (calling the conversion method From):
List<int> list = new List<int>();
ObjectResult result = ObjectResult.From(list);
The From method might look like this:
public class ObjectResult
{
//...
public static ObjectResult From<T>(T arg) { return new ObjectResult<T>(arg); }
//...
}
public class ObjectResult<T> : ObjectResult
{
//...
public ObjectResult(T obj) { /* ... some implementation ... */ }
//...
}
This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 8 years ago.
I'm using .Net framework 2.0 to try and do the following:
I've an external service which returns a list of int. In turn I use each int to find a corresponding Type which has an Attribute with a property, key; the value of that property matches the search parameter.
Using the Type t I'd like to call a generic method, but I'm unable to do this. As I will only know the Type at runtime, I suspect I may have to use reflection to invoke the generic method GetResultsForType - is this the correct way to go about this?
[MyAttribute(key1 = 1)]
class A{
//some properties
}
[MyAttribute(key1 = 2)]
class B{
//some properties
}
//and so on (for hundreds of classes). The key is unique for every class.
public class Foo{
public void DoSomething(){
IList<int> keys = QuerySomeExternalService();
Assembly asm = LoadAssemblyFromSomewhere();
Type[] types = asm.GetTypes();
foreach(int key in keys){
Type t = SearchTypesForAttributeWithMatchingKey(types, key); //I omitted caching of all the keys and Types into a Dictionary on first iteration for brevity.
IList<t> results = GetResultsForType<t>(); //won't work!
//do something with the results
}
}
Type SearchTypesForAttributeWithMatchingKey(Type[] types, int key){
foreach(Type t in types){
object[] attributes = t.GetCustomAttributes(typeof(MyAttribute),false);
MyAttribute myAtt = attributes[0] as MyAttribute;
if(myAtt.Key == key) return t;
}
}
IList<T> GetResultsForType<T>(){
IList<T> results = new List<T>();
bool querySuccess = true;
while(querySuccess){
T result;
querySuccess = QueryExternalService<T>(out result);
results.Add(result);
}
return results;
}
}
Yes you have to use reflection to call a generic method using a System.Type rather than a generic parameterization. You can use the method on methodInfo MakeGenericMethod(params Type[]) after finding the generic method.
If you know the method is called often but with a small number of types, you can cache delegates to invoke the right version.
Something like::
typeof(Foo).GetMethod("YourMethod").MakeGenericMethod(type).Invoke(new[]{parameters});