class SetMap : KeyedCollection<Type, object>
{
public HashSet<T> Use<T>(IEnumerable<T> sourceData)
{
var set = new HashSet<T>(sourceData);
if (Contains(typeof(T)))
{
Remove(typeof(T));
}
Add(set);
return set;
}
public HashSet<T> Get <T>()
{
return (HashSet<T>) this[typeof(T)];
}
protected override Type GetKeyForItem(object item)
{
return item.GetType().GetGenericArguments().Single();
}
}
would anyone clarify this for me pls. return (HashSet) this[typeof(T)]; with example if possible.
thank you
return (HashSet) this[typeof(T)];
Let me split the statement into parts.
(1) this[...] means using the indexer of this. And this basically means "this object".
(2) The indexer accepts a Type. And in this call to the indexer, the argument is typeof(T).
(3) typeof gets a Type object that corresponds to the type in the (). In this case, the generic type parameter T. And the indexer returns an object.
The parameter (Type) and return type (object) of the indexer can be inferred from the base type of the class: KeyedCollection<Type, object>. I think you can understand this.
(4) The value returned by the indexer gets casted into a HashSet<T>. Again, T is the generic type argument.
(5) The value gets returned to the caller by the return statement.
For more information:
Indexers: https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
Generics: https://msdn.microsoft.com/en-us/library/512aeb7t.aspx
Casting: https://msdn.microsoft.com/en-us/library/ms173105.aspx\
KeyedCollection: https://msdn.microsoft.com/en-us/library/ms132438(v=vs.110).aspx
typeof: https://msdn.microsoft.com/en-us/library/58918ffs.aspx
It is using generics. A modern programming concept that makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.
In your example it is defining a hashset that can hold any type.
Read the MSDN documentation in the links I've provided and if you have a more specific questions post them here.
Related
I think I know why but it would be much appreciated if someone could enlighten me as to why, when I write this method where IStoreable is an interface:
public bool TryRetrieveItem<T>(string itemKey, out T item) where T : IStoreable
{
item = default(T);
if (this.RetrieveItem(itemKey, out IStoreable retItem))
{
item = (retItem as T);
return true;
}
return false;
}
Complains about this item = (retItem as T);
And in order to fix that I have to add the class restriction to the where clause.
Why should I do that since I'm already restricting T on an interface? Is it because interfaces can be implemented by non-reference types? Or maybe I got the details wrong?
Is it because interfaces can be implemented by non-reference types?
Yes.
The as operator you are using can only perform reference type conversions. It tries to convert the variable to the desired type. If it fails, the expression evaluates to null. It doesn't work on value types because value types cannot be null.
This is why you have to constrain T to a class.
Alternatively, you can change the as to a cast.
item = (T)retItem;
If you do this, you don't need a reference type constraint on T, but it will throw an exception when it fails to convert.
A third alternative would be to check the type of retItem using pattern matching:
if (retItem is T t) {
item = t;
}
I have a generic method
public async Task Save<T>(T aggregate) where T : AggregateRoot
From this method I call another generic method
var indexRegistrations = IndexRegistrar.GetAll<T>();
Now in this second generic method, I want to get the real type of T, which is a subtype of AggregateRoot:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot
{
return _register.FindAll(r => r.aggregateType == typeof(T));
}
However, the typeof(T) always returns AggregateRoot.
How can I get the real type (=subtype of AggregateRoot) of T?
typeof(T) is correct here.
I tested your case, and typeof(T) always returns the "true" class, not just the type requirement.
public class BaseClass { }
public class DerivedClass: BaseClass { }
public class GenericClass<T> where T : BaseClass
{
public string TypeOf = typeof(T).ToString();
}
public class GenericSuperClass<T> where T : BaseClass
{
public GenericClass<T> Sub = new GenericClass<T>();
}
static void Main(string[] args)
{
Console.WriteLine("1 - " + (new GenericClass<BaseClass>()).TypeOf);
Console.WriteLine("2 - " + (new GenericClass<DerivedClass>()).TypeOf);
Console.WriteLine("3 - " + (new GenericSuperClass<BaseClass>()).Sub.TypeOf);
Console.WriteLine("4 - " + (new GenericSuperClass<DerivedClass>()).Sub.TypeOf);
Console.ReadLine();
}
The output:
1 - BaseClass
2 - DerivedClass
3 - BaseClass
4 - DerivedClass
Note that I've simplified the classnames from the values that are actually returned (e.g Sandbox.TestConsole.Program+DerivedClass).
This directly contradicts your claim that you only ever get the base type (AggregateRoot, in your case).
Reflection is an exception to this.
I can think of one exception to this: when your type is only defined at runtime (e.g. generated from a type name (String)).
However, as this StackOverflow answer explains, generics are intended to provide compile time type safety.
It's not impossible to use reflection to instantiate a generic class at runtime. But when you do so, you are inherently preventing the validity of information (e.g. type names) that are decided at compile-time.
MSDN's page on typeof implicitly states that the return value of typeof is the compile-time type.
Combining these two facts, this means that when you use reflection (i.e. deciding the type at runtime), you cannot rely on typeof (as this returns the compile time type).
The linked MSDN page also mentions how to find the runtime type:
To obtain the run-time type of an expression, you can use the .NET Framework method GetType, as in the following example:
int i = 0;
System.Type type = i.GetType();
However, do note that the GetType() method is only available on an instantiated object, not on a generic type parameter. Generic type parameters are not really types, they are much closer to "type placeholders".
You will need either pass the type as a parameter, or an instantiated object (of the appropriate type).
Conclusion:
If you are using types that are known at compile time, then you can simply use typeof(T), as my example has shown.
If you are deciding the type on runtime using reflection, then you cannot rely on the information provided by typeof(T), and will therefore be required to supply the type. Either you supply it as a Type parameter, or you supply it via an instantiated object, whose runtime type can accurately be tested using the GetType() method.
However, if you are already deciding the type on runtime, then you are better off passing the type itself as a parameter. If you're using reflection here, that means that you must at some point have known which type you wanted to use. Therefore, simply pass that known type as a parameter, which you can then use for your subsequent business logic.
I cannot think of a single scenario in which you aren't either (a) using a type that is known at compile time, nor (b) aware (at runtime) of the type you've decided to use.
As #Flater answer stated, typeof is valid is this case, unless when you instanciated these objects you did not know their types.
So this solution will work for types instanciated at run-time. It will also work if you knew the type at compile time, but it is more complicated and adds complexity.
A solution would be to be able to have an instance of your type, in order to call GetType() on that instance, this would give you the lowest inheriting type of the object.
So, to get an instance, either you change your function and ask for an object to be passed along:
public static List<IndexRegistration> GetAll<T>(T instance) where T : AggregateRoot
{
return _register.FindAll(r => r.aggregateType == instance.GetType());
}
Either you create an instance at run-time, and retrieve the type. This require that you mark the generic type as having a parameterless constructor:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot, New()
{
T instance = new T();
return _register.FindAll(r => r.aggregateType == instance.GetType());
}
There is a similar answer for your question:
when-and-where-to-use-gettype-or-typeof.
Generally typeof operator checks for a known at compile-time type. So it will always be AggregateRoot in your case.
To match T itself together with all its inheritors use IsAssignableFrom reflection method, instead of type object comparision:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot
{
return _register.FindAll(r => typeof(T).IsAssignableFrom(r.aggregateType));
}
I have a class with a dictionary that maps Type keys to objects that implement some interface IWhatever.
I wish to create a generic function that gets a Type as input and returns the object mapped to that type in the dictionary.
Something like :
public T get<T>(Type type)
Where T is an instance of type and type implements IWhatever.
I don't want to return Object or even Iwhatever but objects of the given type. the type of the return objects can clearly be infered at compile time. so I assume it should be possible.
I have managed to do this in java:
public T get<T>(Class<T extends IWhatever> type) { // implementation }
Is there any way to achieve this in C# ? if not, why not and what alternatives would you suggest ?
I think you want:
public T Get<T>() where T : IWhatever { ... }
For more information, see Constraints on Type Parameters (C# Programming Guide).
This is of course only useful when the client can provide the type argument easily at compile-time. Internally, your method may need a lot of nastiness, e.g.:
return (T) myDict[typeof(T)];
I think you are being misled by Java's erasure. Consider the following Java code from your post (edited to make it valid code):
public <T extends IWhatever> T get(Class<T> type) { // implementation }
In this case, the type parameter is only required because the generic type information is only available at compile time. This is not true in C#, where you can write the following:
public T Get<T>()
where T : IWhatever
{
Type type = typeof(T);
// rest of implementation
}
From your first two sentences, what you want I think is the following. You have to decide on some attribute of your types that will be unique. You could make sure that all the types you have include the GUID attribute.
public class MyClass
{
private Dictionary<GUID, object> _myDictionary;
public AddObject(object objectToAdd)
{
_myDictionary.Add(objectToAdd.GUID, objectToAdd);
}
public object GetObject(Type typeToGet)
{
return _myDictionary[typeToGet.GUID];
}
}
If the dictionary needs to contain multiple objects of each type, then the dictionary values can be lists of objects.
bool IsTypeAGenericList(Type listType)
{
typeof(IList<>).IsAssignableFrom(listType.GetGenericTypeDefinition())
}
returns false when given typeof(List<int>).
I assume this is because the two type parameters can be different, correct?
Actually, this works:
public static bool IsGenericList(Type type)
{
if (!type.IsGenericType)
return false;
var genericArguments = type.GetGenericArguments();
if (genericArguments.Length != 1)
return false;
var listType = typeof (IList<>).MakeGenericType(genericArguments);
return listType.IsAssignableFrom(type);
}
This really has to do with open constructed types.
When you say:
class List<T> : IList<T>
You're actually saying: my class is called List, it has one type parameter called T, and it implements the interface that is constructed from IList<> using the same T. So the T in the definition part and the T in the "implements" part both refer to the same type parameter -- you declare it before the colon, then you immediately reference it after the colon.
It gets confusing because IList<>'s type parameter is also called T -- but that is a different type parameter entirely. So let's re-declare our concrete class like this:
class List<U> : IList<U>
This is completely equivalent to the above, only now we can say "U" when we refer to the type parameter of List, and T when we refer to the one from IList. They're different types.
Now it gets easier to see why the generic type definition List<U> (which is what you mean when you say typeof(List<>)) does not implement the generifc type definition IList<T> (which is what you mean when you say typeof(IList<>)), but rather it implements the open generic constructed type IList<U> (that is, IList constructed with List's own type paremeter).
So basically, generic type definitions never inherit or implement other generic type definitions -- they usually implement open constructed types using their own type parameters with other generic type definitions.
Ripper234's answer shows how to handle this particular case using Reflection, so I won't repeat it; I just wanted to clarify the relationship between those types, and I hope it came out at least somewhat intelligible.
I guess the method doesn't really make sense, because an instance is never of the generic type - it's always constructed with a particular type argument.
In other words, you could never have an "open" variable to assign into, nor a reference to an open instance to use as the value for the assignment.
As you say, you don't know whether the type parameters will be the same - so (for instance) you could define:
class BizarreList<T> : IList<int>
It feels like there should be some way of expressing the relationship though...
Here's the extension method from AutoMapper:
public static bool IsCollectionType(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>))
{
return true;
}
IEnumerable<Type> genericInterfaces = type.GetInterfaces().Where(t => t.IsGenericType);
IEnumerable<Type> baseDefinitions = genericInterfaces.Select(t => t.GetGenericTypeDefinition());
var isCollectionType = baseDefinitions.Any(t => t == typeof(ICollection<>));
return isCollectionType;
}
I want to make a method:
object Execute()
{
return type.InvokeMember(..);
}
to accept a generic parameter:
T Execute<T>()
{
return Execute() as T;
/* doesn't work:
The type parameter 'T' cannot be used with the 'as' operator because
it does not have a class type constraint nor a 'class' constraint */
// also neither typeof(T), nor T.GetType() are possible
return (T) Execute(); // ok
}
But I think operator as will be very useful: if result type isn't T method will return null, instead of an exception! Is it possible to do?
You need to add
where T : class
to your method declaration, e.g.
T Execute<T>() where T : class
{
By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:
MyClass c = whatever.Execute() as MyClass;
Or if they want to throw on fail:
MyClass c = (MyClass)whatever.Execute();
The generic wrapper method looks like this:
MyClass c = whatever.Execute<MyClass>();
All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.
(This may be irrelevant to you if your example is simplified from your actual code).
You cannot use the as operator with a generic type with no restriction. Since the as operator uses null to represent that it was not of the type, you cannot use it on value types. If you want to use obj as T, T will have to be a reference type.
T Execute<T>() where T : class
{
return Execute() as T;
}
This small piece of code is an exception safe substitution for the as-keyword:
return Execute() is T value ? value : default(T)
It uses the pattern matching feature introduced with C# 7.
Use it, if you don't want to restrict the generic parameter to a reference type
It seems like you are just adding a wrapper method for casting to the type the user wants, thus only adding overhead to the execution. For the user, writing
int result = Execute<int>();
isn't much different from
int result = (int)Execute();
You can use the out modifier to write the result into a variable in the caller's scope, and return a boolean flag to tell whether it succeeded:
bool Execute<T>(out T result) where T : class
{
result = Execute() as T;
return result != null;
}
Is there a chance that Execute() might return a value type? If so, then you need Earwicker's method for class types, and another generic method for value types. Might look like this:
Nullable<T> ExecuteForValueType<T> where T : struct
The logic inside that method would say
object rawResult = Execute();
Then, you'd have to get the type of rawResult and see if it can be assigned to T:
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
Finally, make your original Execute message figure out which T is has (class or struct type), and call the appropriate implementation.
Note: This is from rough memory. I did this about a year ago and probably don't remember every detail. Still, I hope pointing you in the general direction helps.