C# casting generic parameter to interface - c#

I need help with casting generic paremetrs down to an interface.
I have prebaked code like this:
public interface InterFoo<T> {...}
public InterFoo<T> specialFoo<T>() where T : InterFoo<T> {...}
public InterFoo<T> regularFoo<T>() {...}
and i want to implement something like this
public InterFoo<T> adaptiveFoo<T>()
{
if (T is InterFoo<T>)
return specialFoo<T as InterFoo>();
return regularFoo<T>();
}
at this point I cant find any solution so anything would be helpful, thanks.
EDIT: originally the functions had returned an int but that has a simpler solution that is incompatible with the code's intended purpose, the functions have been changed to request a generic type.

The is and as operators only compile for types that the compiler knows can be null (nullable value types or reference types).
You can try a call to IsAssignableFrom:
public int adaptiveFoo<T>()
{
if (typeof(InterFoo<T>).IsAssignableFrom(typeof(T))
return specialFoo<InterFoo>();
return regularFoo<T>();
}
** Update to reflect changes in question **
Type constraints are, unfortunately viral, in order for your method to compile (when keeping with strict type checking from the compiler) you would need the constraint to be added to this method also. However, reflection can circumvent this restriction:
Your method would be:
public InterFoo<T> adaptiveFoo<T>()
{
if (typeof(InterFoo<T>).IsAssignableFrom(typeof(T))
{
var method = typeof (Class1).GetMethod("specialFoo");
var genericMethod = method.MakeGenericMethod(typeof(T));
return (Interfoo<T>)method.Invoke(this, null);
}
return regularFoo<T>();
}

Related

Cast Enum to return Generic C# 7.3

More than probably this is a conceptual misunderstood but I want to know why.
I've a static method that can return one generic value T, and it also receives a string.
public static T GetWordType<T>(string word) where T : System.Enum
{
if (typeof(T) == typeof(ActionType))
{
foreach (Word<ActionType> action in actionsList)
{
if (action.synonims.Contains(word))
return action.type;
}
return ActionType.None;
}
return WordType.None;
}
All returns gives me a cast error with the title "You cannot convert implicitly Action.ActionType to T".
Why?
My Action class is declared inheriting from an abstract Word Class defined as follows:
public abstract class Word<T> where T : System.Enum
{
public List<string> synonims;
public T type;
}
I'm clearly messing and overcomplicating this up, but I can't figure it out how should be implemented. Thanks for the help.
EDIT: As a petition from Pavel Anikhouski
my ActionType enum is declared inside Action class like this:
class Action : Word<ActionType>
{
public enum ActionType
{
Open, Close, Shutdown, Stop, Send, Save, Load, Move, Add, Cancel, None
}
}
and my WordType enum is a test enum, could be any enum at this moment, is just set it to test the returning of different enums. Something like:
public enum WordType
{
None, Test
}
Take a look at this when I take out what’s inside of your if:
public static T GetWordType<T>(string word) where T : System.Enum
{
if (typeof(T) == typeof(ActionType))
{ … }
return ActionType.Cancel;
}
As you can see, you check whether T is ActionType. If it is not, then you return ActionType.Cancel which obviously is an ActionType. But your method is supposed to return T which you have just proven not to be ActionType.
So instead of T, you actually want your method to return ActionType in all cases because that’s exactly what you are doing:
public static ActionType GetWordType<T>(string word) where T : System.Enum
{
if (typeof(T) == typeof(ActionType))
{
foreach (Word<ActionType> action in actionsList)
{
if (action.synonims.Contains(word))
return action.type;
}
return ActionType.None;
}
return ActionType.Cancel;
}
And at this point one could argue that you don’t even need a generic method here because you are not really doing much with that parameterized type T other than checking for its exact type.
It’s generally a bad idea to deal with actual possible types for T inside generic methods. It makes your method, which is supposed to be generic for all compatible types, brittle since you are looking for exact types but actually deal with an infinite number of types T that you cannot plan for.
You have since changed your question so that it returns ActionType.None inside of the if and WordType.None outside of the condition. You are still returning concrete types so you cannot have your method return T. And this will also not work because ActionType and WordType are separate types, and enums do not allow inheritance which could possibly make this work for other return types.
If you cannot know the return type at compile time, then you would have to return object and interpret the result at run time, to see what value it actually is.
If you actually meant the return value WordType.None to be a value of the enum type T, then what you could do is always return the default for the enum. That way, you can have your method be generic with a custom handling for ActionType:
public static T GetWordType<T>(string word) where T : System.Enum
{
if (typeof(T) == typeof(ActionType))
{
// you know `T` is `ActionType`, so you can cast to `T`:
return (T)(object)ActionType.None;
}
// since you don’t know `T`, you cannot refer to actual values on
// the imaginary enum `T`; you can however use the default value
// (which will be the value 0, by default the first enum value)
return default(T);
}

Method return type like Generic Class Type

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.

Why can I not infer an interface from a constrained generic collection?

I have a piece of code that works like this:
public IEnumerable<ICacheMember> Flubvert( IEnumerable<ICacheMember> members )
{
// do some stuff to members
return members;
}
However I am confused as to why I can't do this:
public IEnumerable<T> ExecuteFlubversion<T>( IEnumerable<T> memberList ) where T: class,ICacheMember
{
return Flubvert( memberList );
}
Surely the constraint on the generic should guarantee that memberListis an IEnumerable of the ICacheMembertype? Do I really need to convert a collection of existing ( but implicit ) ICacheMember objects into explicit ICacheMember objects and then convert them back afterwards? I can understand that I might need to convert them back given the method signature of Flubvert but I don't see why I should have to convert them in the method call. This is what I am doing in the working code but it seems completely out of keeping with the generally elegant behaviour of generics so I think I must be misunderstanding something about how this is supposed to operate.
First of all covariance of IEnumerable<out T> (and other generic types) only works when T is a reference type, so you need:
public IEnumerable<ICacheMember> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T: class, ICacheMember // NOTE 'class'
{
var flub = Flubvert(memberList); // can you call with 'memberList'?
return flub; // can you return that type?
// depending on what 'Flubvert' does, maybe return 'IEnumerable<T>'
// and say:
// return (IEnumerable<T>)flub;
}
Also note that I changed the return value. The C# compiler cannot guarantee that the returned object from the non-generic Flubvert method is anything more specific than IEnumerable<ICacheMember>.
Lets say you have:
interface ICacheMemberSub : ICacheMember
{
...
}
And you call your function like this:
ExecuteFlubversion<ICacheMemberSub>(cacheMember);
This function will try to return an object with type IEnumerable<ICacheMember>, and that is not necessarily castable to IEnumerable<ICacheMemberSub>, hence the error.
At risk of not directly answering the question, can you change the signature of Flubvert to a generic? If you make Flubvert generic, the rest of the method code will stay the same and you can still assume that the members will be implementers of ICacheMember.
public IEnumerable<T> Flubvert<T>(IEnumerable<T> members)
where T : class, ICacheMember
{
// do some stuff to members
return members;
}
public IEnumerable<T> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T : class,ICacheMember
{
return Flubvert(memberList);
}

Generics, Nullable, Type inference and function signature conflict

I've this code :
public async static Task<T?> RequestValue1<T>(Command requestCommand)
where T : struct
{
// Whatever
}
public async static Task<T> RequestValue2<T>(Command requestCommand)
where T : class
{
// Whatever
}
I want to have the same name for my two methods. Is this even possible ?
My problems:
I have to write two different methods because of the return type (I want it to be null if the request failed or a value if the request succeed) which is Nullable<T> if T is a value type, and an instance of T if T is a reference type.
async doesn't allow ref/out, so without a method argument of type T, T isn't inferred and my two methods cannot have the same name (signature conflict, as generic constraints doesn't works for signature conflict resolution if T isn't inferred)
Currently this code works but I don't like this strange function calls between "RequestValue1" and "RequestValue2".
You could create your own Option type and use that to indicate if a value is returned or not:
public async static Task<Option<T>> RequestValue<T>(Command requestCommand) {
...
}
Update: the intent of the Option<T> type is to replace nulls and Nullable<T>s, but if you'd still like to use them, you can use these extension methods to bridge the gap:
public static class OptionExtensions {
public static T? GetNullableValue<T>(this Option<T> option) where T : struct {
return option.HasValue ? (T?)option.Value : null;
}
public static T GetValueOrNull<T>(this Option<T> option) where T : class {
return option.HasValue ? option.Value : null;
}
}
You can drop the constraint, and make the callers pass a Nullable<T> type to your method (i.e. call RequestValue<int?>(cmd) instead of RequestValue<int>(cmd)). You can ensure nullability at runtime, like this:
public async static Task<T> RequestValue<T>(object arg) {
var t = typeof (T);
if (!t.IsClass && (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Nullable<>))) {
throw new ArgumentException("T");
}
// Whatever
}
One can have method signatures like:
static void test1<T>(Nullable<T> param) where T:struct;
static void test1<T>(T param) where T:class;
without conflict. Attempting to pass a non-nullable struct type will fail, but the compiler will have no problem selecting an overload given a parameter of either a nullable type or a class type.
Your scenario is a little different, since you aren't passing a parameter of a particular type; you're just trying to pass the type itself. Without an actual parameter of the type, the compiler won't be able to decide that a Nullable<T> is a better fit for one method than the other. My inclination would be to offer a method which uses some other means than the nullity of the result to indicate success or failure. The normal Try pattern would look like:
static bool RequestValue1<T>(Command requestCommand, out Task<T> Result);
I don't especially like that pattern, since it's impossible for Result to be covariant or participate in type inference. An alternative would be:
static Task<T> RequestValue1<T>(Command requestCommand, out bool Success);
Such a form would have no problem with covariance. An alternative form would be something like:
static Task<T> RequestValue1<T>(Command requestCommand, out ResultStatus Status);
where ResultStatus would be a type with a Succeeded method that returns True in case of success, but could have other members that explain what's wrong in case of failure. If it's an immutable abstract type which defines a singleton Success instance for use when things work, it could be extended in future to provide an arbitrary level of detail when things don't work without causing any GC pressure when they do.
Unfortunately, even the forms where the out parameter type doesn't depend upon T can't be used in some contexts. To allow for that, one could define a struct type CommandResult<T> which combines a T with a success indicator, in a fashion conceptually similar to Nullable<T> but without annoying struct constraint on its parameter type. The success indicator could either be a bool, or could be a status indicator as described above.

C# - How are we supposed to implement default(T) in Interfaces?

Put default(T) in an interface. Explicitly implement the interface. The result does not compile
public interface IWhatever<T>
{
List<T> Foo(T BarObject = default(T));
}
public class ConcreteWhatever: IWhatever<ConcreteWhatever>
{
List<ConcreteWhatever> Foo(ConcreteWhatever BarObject = default(T)) {}
}
I fully expect default(ConcreteWhatever). What I get is default(T) which results in a compilation error.
I just go in and replace default(T) with null and things are fine. But this is hideous. Why is this happening?
You don't have a T in this case, because ConcreteWherever isn't a generic type.
If you want default(ConcreteWhatever) then that's the code you should write.
Are you just complaining about the code auto-generated by Visual Studio? If so, that's a reasonable complaint, but it would be worth being explicit about it... (Note that you're not using explicit interface implementation here - otherwise it would be declared as IWhatever<ConcreteWhatever>.Foo. You don't really have properly implicit implementation either, as otherwise it should be public...)
EDIT: I've just tried the same thing myself, and seen the same result, except the method is made public. Looks like it's just a fault with Visual Studio - I suggest you create a Connect request for it. It's a relatively rare situation though, I suspect - creating a generic interface which specifies an optional parameter which uses the default value of a type parameter as the value...
Shouldn't this line:
List<ConcreteWhatever> Foo(ConcreteWhatever BarObject = default(T)) {}
be:
List<ConcreteWhatever> Foo(ConcreteWhatever BarObject = default(ConcreteWhatever)) {}
public interface IWhatever<T>
{
List<T> Foo(T BarObject = default(T));
}
public class ConcreteWhatever : IWhatever<ConcreteWhatever>
{
public List<ConcreteWhatever> Foo(ConcreteWhatever BarObject = default(ConcreteWhatever))
{
return null; // replace with proper code
}
}

Categories

Resources