Is there any way to create an extension method whose parameter's only constraint is having specifically-named properties.
e.g.:
public static bool IsMixed<T>(this T obj) where T:?
{
return obj.IsThis && obj.IsThat;
}
I tried to declare the obj as dynamic but it's not allowed.
This feature is often called "duck typing". (Because when you call foo.Quack() all you care about is that it quacks like a duck.) Non-dynamic duck typing is not a feature of C#, sorry!
If you really have no type information about the argument, you can use dynamic in C# 4:
public static bool IsAllThat(this object x)
{
dynamic d = x;
return d.IsThis || d.IsThat;
}
But it would be better to come up with some interface or some such thing that describes the types at compile time.
you would have to get T to implement an interface, then use that in the constraint.
While you cannot do what you're looking to with generic constraints, you could use reflection to check the type at runtime to determine whether it has those properties and dynamically get their values.
Disclaimer: I'm doing this off the top of my head, I may be slightly off in the implementation.
public static bool IsMixed(this object obj)
{
Type type = obj.GetType();
PropertyInfo isThisProperty = type.GetProperty("IsThis", typeof(bool));
PropertyInfo isThatProperty = type.GetProperty("IsThat", typeof(bool));
if (isThisProperty != null && isThatProperty != null)
{
bool isThis = isThisProperty.GetValue(this, null);
bool isThat = isThatProperty.GetValue(this, null);
return isThis && isThat;
}
else
{
throw new ArgumentException(
"Object must have properties IsThis and IsThat.",
"obj"
);
}
}
pretty much the only way to do this is to have an interface as the base of the class you are tring to operate on:
interface iMyInterface
{
}
public static bool IsMixed<T>(this T obj) where T: iMyInterface
{
return obj.IsThis && obj.IsThat;
}
Related
I have a type that uses generics. Let's call it FlowerDescriptor<T> some flowers are described using numbers, others using strings etc.
so FlowerDescriptor<int>; FlowerDescriptor<string>; etc
I want a mechanism (probably extension methods) for doing 2 things
seeing if something is a FlowerDescriptor and
seeing what the descriptor is.
I.e.
FlowerDescriptor<string>.GetType().IsFlowerDescriptor == true
string.GetType().IsFlowerDescriptor == false.
equally I might derive from FlowerDescriptor<int> i.e. class NumberedFlower: FlowerDescriptor<int>
new NumberedFlower.GetType().IsFlowerDesriptor == true;
as above but returns the type
FlowerDescriptor<string>.GetType().GetFlowerDescriptor() == typeof(string)
FlowerDescriptor<int>.GetType().GetFlowerDescriptor() == typeof(int)
new NumberedFlower.GetType().GetFlowerDescriptor() == typeof(int)
I have played about with variations of IsAssignableFrom and it feels like that ought to work with typeof(FlowerDescriptor<>).IsAssignableFrom(typeof(FlowerDescriptor<string>))
but it doesn't work. If it add the generic type however it does.
I am currently exploring GetInterfaces to know available interfaces. It'd be great to actually understand what I am doing wrong too..
Unless you want to add interfaces into the mix, the only choice you have is to
Detect that the type is actually a FlowerDescriptor<T>
or detect that the type inherits from something that is a FlowerDescriptor<T>
Unfortunately I don't think you can use IsAssignableFrom when it comes to open generics which means we're left with walking the inheritance chain up to the base classes.
Here is an example piece of code that would do the right thing:
public static bool IsFlowerDescriptor(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(FlowerDescriptor<>))
return true;
if (type.BaseType != null)
return type.BaseType.IsFlowerDescriptor();
return false;
}
Here's a .NET Fiddle you can experiment with.
I would not expect the string or int class to know if its a descriptor, it makes a lot more sense to get that information from the FlowerDescriptor.
That being said if you want to use reflection you could get the generic type definition from the FlowerDescriptor instance
FlowerDescriptor<int> f = new FlowerDescriptor<int>();
Type t = f.GetType();
Type[] typeArguments = t.GetGenericArguments();
//check if type you care about is in typeArguments
Here is how you would get those two values:
bool isFlowerDescriptor = x is FlowerDescriptor<object>;
Type descriptorType = x.GetType().GetGenericArguments()[0];
You could wrap these in extension methods if you like. And add null-checks etc.
You might consider having a non-generic base class. Then your structure could look like:
public abstract class FlowerDescriptor { }
public class FlowerDescriptor<T> : FlowerDescriptor { }
public class NumberedFlower : FlowerDescriptor<int> { }
Your 2 extensions would be:
public static class Extensions
{
public static bool IsFlowerDescriptor(this object o)
{
return o is FlowerDescriptor;
}
public static Type GetFlowerDescriptor<T>(this FlowerDescriptor<T> o)
{
return typeof (T);
}
}
and you'd use it like:
public static void Main()
{
Console.WriteLine(new NumberedFlower().IsFlowerDescriptor()); //true
Console.WriteLine(new NumberedFlower().GetFlowerDescriptor()); //System.Int32
}
Generics have an adverse effect when it comes to reflecting over and comparing types, because a FlowerDescriptor<int> is a different type from FlowerDescriptor<string>. This is something I have not found a good rhythm for.
The title says it all, here's the same with some formatting:
Why can't I write
public bool IsHashSet(object obj)
{
return obj is HashSet<>;
}
but this is okay:
public bool IsHashSet(object obj)
{
return obj.GetType() == typeof(HashSet<>);
}
(The same goes for all generics and isn't limited to HashSet)
Your function
public bool IsHashSet(object obj)
{
return obj.GetType() == typeof(HashSet<>);
}
will return false for every possible value of obj, except null, in which case it will throw a NullReferenceException. It will not check if obj is a hash set. typeof(HashSet<int>) and typeof(HashSet<>) are two different types.
It is for that same reason that obj is HashSet<> is rejected. It's completely useless. The only difference between the two functions is that one is useless in a way the compiler knows about, and the other is useless in a way the compiler doesn't know about.
You can use type.IsGenericType and type.GetGenericTypeDefinition(), then compare the result of the latter to typeof(HashSet<>). However, you should ask yourself if that is useful: obj is HashSet<int> would also evaluate to true if obj is derived from HashSet<int>. Working with obj.GetType() would require you to check the class hierarchy yourself.
You can write a reusable helper function to check this for other generic types too:
public static bool IsInstanceOfGenericType(object obj, Type genericType) {
if (obj == null)
return false;
var type = obj.GetType();
while (type != null) {
if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType)
return true;
type = type.BaseType;
}
return false;
}
You can call this as IsInstanceOfGenericType(someObject, typeof(HashSet<>)).
To respond to your comments:
In my understanding of HashSet<> would mean HashSet of any generic, so maybe this would work typeof(HashSet<>).IsAssignableFrom(HashSet<int>)
It would not. It's possible you're thinking of Java, which as I understand it does have something like that, but C# does not. HashSet<int> and HashSet<> are related types, but their relation is not one related to inheritance.
if not whats the meaning of HashSet<>
It is the HashSet<T> type before it has got any specific type argument. It can be used to construct the real types, for example after var t = typeof(int);, typeof(HashSet<>).MakeGenericType(t) can be used to get typeof(HashSet<int>). It can be useful if t is not known at compile-time. But outside of such dynamic type construction, it is not meaningful.
and why is it valid to write in a typeof() but not in is HashSet<>?
It's not valid with is HashSet<> because it would never be meaningful. It is impossible to construct any object whose type is HashSet<>.
Neither actually works, it's just that the first one will fail at compile time. What you probably want is something like this:
public bool IsHashSet(object obj)
{
if (obj != null)
{
var t = obj.GetType();
if (t.IsGenericType) {
return t.GetGenericTypeDefinition() == typeof(HashSet<>);
}
}
return false;
}
Say I have the following class:
public class General<T> { }
And I want to find out if an object is of that type.
I know I can use reflection to find out whether the object is of that generic type with Type.GetGenericTypeDefinition, but I want to avoid that.
Is it possible to do something like obj is General<T>, or obj.GetType().IsAssignableFrom(typeof(General<T>))?
I'm quite surprised that I couldn't find a similar question, although I may have used wrong keywords in my searches.
You can do this:
var obj = new General<int>();
var type = obj.GetType();
var isGeneral =
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(General<>)) ||
type.GetBaseTypes().Any(x => x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(General<>));
Where GetBaseTypes is the following extension method:
public static IEnumerable<Type> GetBaseTypes(this Type type)
{
if (type.BaseType == null) return type.GetInterfaces();
return new []{type}.Concat(
Enumerable.Repeat(type.BaseType, 1)
.Concat(type.GetInterfaces())
.Concat(type.GetInterfaces().SelectMany<Type, Type>(GetBaseTypes))
.Concat(type.BaseType.GetBaseTypes()));
}
credits to Slacks answer
There are many answers to similar questions, but they all require reflection to walk up the type hierarchy. I suspect there is no better way. If performance is critical, caching the result maybe an option. Here is an example using a ConcurrentDictionary as a simple cache. Then the cost is reduced to a simple type lookup (via GetType) and a ConcurrentDictionary lookup after the cache has been initialized.
using System.Collections.Concurrent;
private static ConcurrentDictionary<Tuple<Type,Type>, bool> cache = new ConcurrentDictionary<Tuple<Type,Type>, bool>();
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type generic) {
var input = Tuple.Create(toCheck, generic);
bool isSubclass = cache.GetOrAdd(input, key => IsSubclassOfRawGenericInternal(toCheck, generic));
return isSubclass;
}
private static bool IsSubclassOfRawGenericInternal(Type toCheck, Type generic) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
And you would use it like this:
class I : General<int> { }
object o = new I();
Console.WriteLine(o is General<int>); // true
Console.WriteLine(o.GetType().IsSubclassOfRawGeneric(typeof(General<>))); //true
Generic type definitions that are instantiated with type parameters have no relation at all to other generic type instantiations. They also have no relation to the generic type definition. They are completely incompatible when it comes to assignment and runtime casting. If they weren't it would be possible to break the type system.
For that reason runtime casts will not help. You will indeed have to resort to Type.GetGenericTypeDefinition. You can abstract that into a helper function and keep your code relatively clean that way.
If a generic class or interface has members which could be used by code which held a reference in a more general form like Object but didn't have the actual generic type available, such members should be exposed in a non-generic base class or interface. The Framework has in many cases failed to abide by that principle, but there's no reason one must follow their example. For example, a type like IList<T> could have derived from IListBase which included or inherited members like:
int Count {get;}
void Delete(int index);
void Clear();
void Swap(int index1, int index2);
int Compare(int index1, int index2);
// Return an object with a `StoreToIndex(int)` method
// which would store it to the list it came from.
ListItemHolder GetItemHolder(int index);
ListFeatures Features {get;}
None of those members would rely in any way upon the type of items held within the list, and one could write methods to do things like sort a list (if its Features indicated that it was writable and knew how to compare items) without having to know anything about the element type. If a generic interface inherits from a non-generic interface, code needing the non-generic functions could simply cast to the non-generic interface type and use it directly.
For a more generalized solution, that works with any parent type (base class as well as interfaces):
public static bool IsCompatibleWith(this Type type, Type parentType)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (parentType.IsAssignableFrom(type))
{
return true;
}
return type.GetAssignableTypes()
.Where(t => t.IsGenericType)
.Any(t=> t.GetGenericTypeDefinition() == parentType);
}
/// <summary>
/// Gets all parent types including the currrent type.
/// </summary>
public static IEnumerable<Type> GetAssignableTypes(this Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
// First check for interfaces because interface types don't have base classes.
foreach (Type iType in type.GetInterfaces())
{
yield return iType;
}
// Then check for base classes.
do
{
yield return type;
type = type.BaseType;
}
while (type != null);
}
Come up with better method names. Perhaps calling it IsCompatibleWith is misleading. Maybe IsKindOf ? Also, GetAssignableTypes can also be called GetParentTypes but that is also misleading. Naming is hard. Documenting it is better.
Some tests:
IsCompatibleWith(typeof(List<int>), typeof(IList<int>))
true
IsCompatibleWith(typeof(List<>), typeof(IList<>))
true
IsCompatibleWith(typeof(List<int>), typeof(IList<>))
true
IsCompatibleWith(typeof(List<int>), typeof(IList<string>))
false
So I have, say, this type of method:
public ICollection<String> doSomething() { }
Currently, I'm trying to check if the return type of method is of type ICollection. However, in C#, I have to pass in a generic when I do the check. So I can't do, say, "method is ICollection".
The problem is that I don't want to restrict the type of generic when I'm checking. In Java, I could just use a wildcard, but I can't do that in C#. I've thought of trying to use the Type.GetGenericParamterContraints() and trying to stick the first result of it in ICollection's generic constraint to check, but that also didn't work. Anybody have any ideas?
isCollection(MethodInfo method){
Type[] ret = method.ReturnType.GetGenericParametersContraint();
Type a = ret[0];
return method.ReturnType is ICollection<a>;
}
EDIT: Added what I tried.
If it's allowed to be the non-generic System.Collections.ICollection (which is implemented by ICollection<T> too) then it's simply:
typeof(System.Collections.ICollection).IsAssignableFrom(method.ReturnType)
If you only want to compare to generic ICollection<T> (I see no reason to, but you may have your reasons):
method.ReturnType.IsGenericType
&& typeof(ICollection<>)
.IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition())
Note that that doesn't work if the return type is non-generic. So it won't work if there's a class that implements ICollection<T> but isn't generic itself. Meaning it won't catch class Foo : ICollection<string> but it will catch class Foo<T> : ICollection<T>.
The first way will catch both just fine though.
You should be able to do:
MethodInfo method = ... // up to you
var returnType = method.ReturnType;
var isGenericICollection = returnType == typeof(ICollection<>);
Use Type.GetGenericTypeDefinition(), and compare its result with typeof(ICollection<>).
So, to check if the return type of your method is an ICollection, you could do it like this:
method.ReturnType.GetGenericTypeDefinition() == typeof(ICollection<>)
Btw. method.ReturnType is ICollection<a> will never be true because is checks if the type of the first operand is a subtype of the second operand. ReturnType is of type Type though which is not a subtype of some ICollection.
Try this, Use MethodInfo.ReturnType to determine the return type
Use the below method, call `isCollection<string>(method)`
public static bool isCollection<T>(MethodInfo method)
{
return method.ReturnType.Equals(typeof(ICollection<T>));
}
Try this:
class Program
{
public ICollection<string> Foo() { return new List<string>(); }
public static bool TestType()
{
MethodInfo info = typeof(Program).GetMethod("Foo");
return info.ReturnType.GetGenericTypeDefinition() == typeof(ICollection<>);
}
static void Main(string[] args)
{
Console.WriteLine("{0} is ICollection<> : {1}", "Foo", TestType());
}
}
prints Foo is ICollection<> : True.
Surprisingly the following code fails the Assert:
int? wtf = 0;
Assert.IsType<Nullable<int>>(wtf);
So just out curiosity, how can you determine if a given instance is a Nullable<> object or not?
Well firstly, Nullable<T> is a struct, so there isn't an object as such. You can't call GetType(), as that will box the value (at which point you either get null and thus an exception, or a boxed non-nullable value and therefore not the type you want).
(Boxing is what's messing up your assertion here - I would assume that IsType accepts object.)
You can use type inference though to get the type of the variable as a type parameter:
public bool IsNullable<T>(T value)
{
return Nullable.GetUnderlyingType(typeof(T)) != null;
}
That's not a huge amount of use when you know the exact type at compile-time as in your example, but it's useful for generics. (There are alternative ways of implementing it, of course.)
What's your real life situation? I assume it's not an assertion like this, given that you know the answer to this one at compile time.
I like the #jon-skeet answer but it only works if you know the type you are testing against. In our world we are using reflection to open up objects and test values against regex expressions.
simplifying the extension to work for any type worked better for us.
public static bool IsNullable(this Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
generics are life's blood but sometimes... :)
int? i = 0;
var type = TypedReference.GetTargetType(__makeref(i));
var isNullable = type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>);
What namespace is Assert in?
The following returns true as you would expect:
int? wtf = 0;
if (typeof(Nullable<int>).IsInstanceOfType(wtf))
{
// Do things
}
Although its worth noting that typeof(Nullable<int>).IsInstanceOfType(42) also returns true - this is because this method accepts an object and so gets boxed as a Nullable<int>.
Here is what I came up with, as everything else seemed to fail - at least on Portable Class Library / DotNet Core with >= C# 6
Basically you extend generic Type Object and Nullable<T> and use the fact that the static extension method that matches the underlying type is going to be invoked and takes precedence over the generic T extension-method.
public static partial class ObjectExtension
{
public static bool IsNullable<T>(this T self)
{
return false;
}
}
and one for Nullable<T>
public static partial class NullableExtension
{
public static bool IsNullable<T>(this Nullable<T> self) where T : struct
{
return true;
}
}
Using Reflection and type.IsGeneric and type.GetGenericParameters() did not work on my current set of .NET Runtimes.
It works fo me, hope for you too.
public static bool IsNullable(this Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
Based on Vladimir answer:
public static class GenericExtensions
{
public static bool IsNullable<T>(this T item) =>
TypedReference.GetTargetType(__makeref(item)).FullName.Contains("System.Nullable");
}
Usage:
int? nullableInt = 42;
bool nIntIsNullable = nullableInt.IsNullable();
Duration: <2ms on average machine.
Remarks:
Important, this API is not CLS-compliant.
Contains("System.Nullable") can be more specific.
This works for me to check wether a type is Nullable or not..
type.Assembly.FullName.StartsWith("System") && type.Name.Contains("Nullable");
Only this way worked in my case using .net core 7
MyClass mclass = new MyClass();
PropertyInfo[] properties = mclass.GetType().GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
bool nullable = propertyInfo.GetMethod is null ? false : new NullabilityInfoContext().Create(propertyInfo.GetMethod.ReturnParameter).ReadState == NullabilityState.Nullable;
if (nullable)
{
//some script to do
}
}