Check if generic parameter of a class implements an interface - c#

I have a following generic class:
public class SearchResult<T>
{
public int ResultCount { get; set; }
public IEnumerable<T> Result { get; set; }
}
I also have a Bird class, which implements IFlyble interface:
public class Bird : IFlyable
{
public void Fly() {}
}
public interface IFlyable
{
void Fly();
}
I also have a variable res of type object.
How do I check if res is a SearchResult<IFlyable> ?
I tryied this way:
if (res.GetType().IsAssignableFrom(typeof(SearchResult<IFlyable>)))
{
///
}
And this way:
if(res is SearchResult<IFlyable>)
{
///
}
But it does not seems to work.

The problem you are having is probably due to the fact that SearchResult<Bird> is not convertible to SearchResult<IFlyable> because SearchResult<T> is invariant in T.
C# only admitís generic type variance in interfaces and delegates. You need to define an ISearchResult<> interface that is covariant in its generic type.
In your case, if it’s accepatable that T Is only used as an output you could define such interface as follows:
public interface ISearchResult<out T>
{
int ResultCount { get; }
IEnumerable<T> Result { get; }
}
And now a ISearchResult<Bird> is a ISearchResult<IFlyable> because you’ve given the compiler enough information so that it can verify that the conversion is in fact safe

You can also try this using reflection, which also works and no need to create another interface.
static void Main()
{
var sr = new SearchResult<Bird>();
Console.WriteLine(IsSearchResultIFlyable(sr.GetType())
? "sr is SearchResult<IFlyable>"
: "sr is Not SearchResult<IFlyable>");
Console.ReadLine();
}
public static bool IsSearchResultIFlyable(Type t)
{
if (!t.IsGenericType) return false;
if (t.GetGenericTypeDefinition() != typeof(SearchResult<>)) return false;
var gr = t.GetGenericArguments();
return gr.Length == 1 && typeof(IFlyable).IsAssignableFrom(gr[0]);
}

Related

Can not convert type int to T

I run into a compiler error that I am not sure how to resolve it.
Basically, I have a few enum classes described below.
I created abstract classes myTool and myTools deriving from myTool.
The compiler for some reason does not like the way I structured the constructor for MyTools and threw error
CS0030: Can not convert type int to type T.
Please advice me how to resolve this.
public enum TOOLS
{
HAMMER =1,
DRILL = 2,
SCREWDRIVER =3,
VACUUM=4
}
public enum EQUIPMENTS
{
MOWER=1,
TRIMMER=2,
SNOWBLOWER=3
}
public abstract class MyTool
{
protected T _myStuff
int quantity
double price
public MyTool(T t)
{
_myStuff =t;
}
... properties...
}
public abstract class MyTools<T>:myTool<T>
where T:System.Enum
{
protected MyTool<T>[] _myTools;
public MyTool<T> this[int i]=> this._myTools[i];
public MyTools(int count, T t):base(t)
{
_myTools = new MyTools<T>[count];
for (int i=0; i<count;i++)
{
_myTools[i]=(T)(i+1);
}
}
}
You can convert an int into a generic type constrained as System.Enum like this:
T enumValue = (T)Enum.ToObject(typeof(T), intValue);
or simply
T enumValue = (T)(object)intValue;
You can use generic type converter
public static class TConverter
{
public static T ChangeType<T>(object value)
{
return (T)ChangeType(typeof(T), value);
}
public static object ChangeType(Type t, object value)
{
TypeConverter tc = TypeDescriptor.GetConverter(t);
return tc.ConvertFrom(value);
}
public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
{
TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
}
}
and usage:
TConverter.ChangeType<T>(intValue);
it is from here: https://stackoverflow.com/a/1833128/2286743

How to declare a method in an interface with unknown count and type arguments

I'm trying to creating an interface like this:
public interface IProcessable<out T>
{
T Result { get; }
T Execute(params object[] args);
}
I want to have an Execute() method that returns T and be able to accept any type of arguments.
And I want to use it like this:
public class CustomProcess: IProcessable<int>
{
public int Result { get; private set; }
public int Execute(string customArg)
{
/// some codes to return int
}
}
IProcessable<int> will force me to add an Execute method like this:
public int Execute(params object[] args)
{
var customArg= args[0] as string;
if (customArg!= null) //I know that this is not so necessary for `string`
{
return Execute(customArg);
}
throw new Exception();
}
I think, I should have both methods in CustomProcess because of wide acceptable range of object[].
Know I should ask:
Is this kind of interface is acceptable or is a kind of an anti-pattern?
Is there any better way to achieve what I want - create an interface that force class to have Result property and Execute method -?
As #Servy commented, And for making a correct signature; I found my solution like this:
public interface IProcessInput
{
}
public interface IProcessable<in TInput, out TOutput> where TInput : IProcessInput
{
TOutput Result { get; }
TOutput Execute(TInput args);
}
public abstract class ProcessInput: IProcessInput
{
protected ProcessInput(int count)
{
Count = count;
}
public virtual int Count { get; private set; }
}
public class WithoutProcessInput : ProcessInput
{
public WithoutProcessInput() : base(0)
{
}
}
and so on ...

How to find out if a type implements generics base class

Using the example below... how can I find out whether a property is of a type implementing generics class Foo?
public class Foo<TBaz>
{
}
public class Bar
{
public Foo<int> FooInt { get; set; }
public Foo<string> FooString { get; set; }
public double SomeOther { get; set; }
public int GetFooCount()
{
return typeof(Bar).GetProperties().Where(p => p.GetType().IsGenericType).Count();
}
}
If I wanted to find Foo<int>, it would be easy, but how can I find out if it contains Foo<int>, Foo<double> etc...?
I have written the bit of GetFooCount() I have so far...
Thanks
return typeof(Bar).GetProperties().Where(p => p.PropertyType.IsGenericType
&& p.PropertyType.GetGenericTypeDefinition() == typeof(Foo<>)).Count();
Note: this won't automatically work for class NonGenericSubtype : Foo<Blah> {...}, nor will it work for class GenericSubtype<T> : Foo<T> {...} - if you need to handle those, it gets more fun.
For the more general case, you would need something that uses recursion on the type:
public static int GetFooCount()
{
return typeof(Bar).GetProperties()
.Count(p => GetFooType(p.PropertyType) != null);
}
private static Type GetFooType(Type type)
{
while(type != null)
{
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Foo<>))
return type.GetGenericArguments()[0];
type = type.BaseType;
}
return null;
}
Note this also answers "now how do I find T?"

c# list of interface with generic items

My question is somewhat similar to
Generic List of Generic Interfaces not allowed, any alternative approaches?
If I have an interface such as
public interface IPrimitive
{
}
public interface IPrimitive<T> : IPrimitive
{
T Value { get; }
}
public class Star : IPrimitive<string> //must declare T here
{
public string Value { get { return "foobar"; } }
}
public class Sun : IPrimitive<int>
{
public int Value { get { return 0; } }
}
Then I have a list
var myList = new List<IPrimitive>();
myList.Add(new Star());
myList.Add(new Sun());
When looping through this list, how do I get the Value property?
foreach (var item in myList)
{
var value = item.Value; // Value is not defined in IPrimitive so it doesn't know what it is
}
I'm not sure how this is possible.
Thanks,
Rob
You can take advantage of dynamic:
foreach (dynamic item in myList)
{
var value = item.Value;
}
The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time
You could do something like this:
public interface IPrimitive
{
object Value { get; }
}
public interface IPrimitive<T> : IPrimitive
{
new T Value { get; }
}
public class Star : IPrimitive<string> //must declare T here
{
public string Value { get { return "foobar"; } }
object IPrimitive.Value { get { return this.Value; } }
}
public class Sun : IPrimitive<int>
{
public int Value { get { return 0; } }
object IPrimitive.Value { get { return this.Value; } }
}
You're then able to get the value out as an object when you only have IPrimitive.
of course not, your value is going to be of different types..... so you will have to downcast to the real type to get at the different values.
Basically your interface is failing. Its not "A common interface" It's more a "similar interface"
If you don't want to do casting, then you will have to find an interface which is common to both of them.
You can move you Value property to base interface.
public interface IPrimitive
{
object Value { get; }
}
How do you want to procced value in the loop it has different type?

Determine which genric type object is derived from

I have the following classes:
public abstract class CommandBase
{
... Stuff
}
public abstract class Command<TArgumentType>
: CommandBase where TArgumentType : class
{
protected TArgumentType Argument { get; private set; }
protected Command(TArgumentType argument)
{
Argument = argument;
}
}
public abstract class Command<TArgumentType, TReturnType>
: Command<TArgumentType> where TArgumentType : class
{
public TReturnType ReturnValue{ get; protected set; }
protected Command(TArgumentType argument) : base(argument)
{
}
}
How do I determine if an object is of type Command<TArgumentType> or Command<TArgumentType, TReturnType>? I don't know what specific types TArgumentType or TReturnType are. Or should I just do a simple try/catch around:
var returnValue = object.ReturnValue;
If you don't know the type at compile-time, then foo.ReturnValue won't even compile, unless it's of type dynamic.
You can use something like this:
static bool ContainsGenericClassInHierarchy(object value,
Type genericTypeDefinition)
{
Type t = value.GetType();
while (t != null)
{
if (t.IsGenericType
&& t.GetGenericTypeDefinition() == genericTypeDefinition)
{
return true;
}
t = t.BaseType;
}
return false;
}
Call it like this:
// Single type parameter
bool x = ContainsGenericClassInHierarchy(foo, typeof(Command<>));
// Two type parameters
bool y = ContainsGenericClassInHierarchy(foo, typeof(Command<,>));
Note that this won't work for finding implemented interfaces, which is somewhat trickier.

Categories

Resources