C# determining generic type - c#

I have several templated objects that all implement the same interface:
I.E.
MyObject<datatype1> obj1;
MyObject<datatype2> obj2;
MyObject<datatype3> obj3;
I want to store these objects in a List... I think I would do that like this:
private List<MyObject<object>> _myList;
I then want to create a function that takes 1 parameter, being a datatype, to see if an object using that datatype exists in my list.... sorta clueless how to go about this. In Pseudo code it would be:
public bool Exist(DataType T)
{
return (does _myList contain a MyObject<T>?);
}
Some Clarification....
My interface is IMyObject<T>, my objects are MyObject<T>. I have a new class MyObjectManager which I need to have a List of MyObject<T> stored within. I need a function to check if a MyObject<T> exists in that list. The type T are datatypes which were auto-generated using T4.... POCO classes from my Entity Data Model.

You can make a generic function:
public bool Exists<T>() where T : class {
return _myList.OfType<MyObject<T>>().Any();
}
Note that this requires that you know T at compile-time.
If all you have is a System.Type object at runtime, you'll need to use reflection:
public bool Exists(Type t) {
var objectOfT = typeof(MyObject<>).MakeGenericType(t);
return _myList.Any(o => o.GetType() == objectOfT);
}
Note, however, that a List<MyObject<object>> cannot hold a MyObject<SomeType>.
You need to change the list to a List<object>, or make MyObject implement or inherit a non-generic type and make the list contain that type.

How about an extension method?
public static bool HasAny(this IEnumerable source, Type type) {
foreach (object item in source)
if (item != null && item.GetType().Equals(type))
return true;
return false;
}
Usage:
bool hasDataType1 = myList.HasAny(typeof(MyObject<datatype1>));
Note that if you don't want to have to type out typeof(...) -- i.e., if you basically want your Exist method to only care about objects of type MyObject<T>, I'd go with something like SLaks's answer:
public static bool Exist<T>(this IEnumerable source) {
return source.OfType<MyObject<T>>().Any();
}
Also, SLaks is right that you really can't have a List<MyObject<object>> that's full of anything other than objects of type MyObject<object> or some derived class (and MyObject<datatype1>, etc. do not derive from MyObject<object> -- generics don't work that way).
Another way I might suggest to work around the whole "you can't get the type of a generic class using a System.Type object without using reflection" issue would be this: Make your MyObject<T> implement a non-generic interface, like this:
public interface IMyObject {
Type DataType { get; }
}
public class MyObject<T> : IMyObject<T>, IMyObject {
public Type DataType {
get { return typeof(T); }
}
}
Then your list could be a List<IMyObject> (the non-generic interface) and your Exist method could look like this:
public static bool Exist<T>(this IEnumerable source, Type type) {
return source.OfType<IMyObject>().Any(x => x.DataType.Equals(type));
}

Since they all implement the same interface, instead of casting them to object and calling GetType (which can be expensive) why not add a property to your interface called class name (or something)? Then you can use the linq in order to grab that property. And don't forget using System.Linq
using System.Linq;
public bool Exist(List<IMyInterface> objects, IMyInterface typeToCheck)
{
return objects.Any(t => t.ObjectName == typeToCheck.ObjectName);
}

Related

Validation against the non generic attribute of a generic type

I want to validate a class, that has a property of a generic type:
class Foo
{
[ValidHistoryDate]
public MyType<string> bar;
[ValidHistoryDate]
public MyType<int> baz;
[ValidHistoryDate]
public MyType<float> bat;
}
class MyType<T>
{
public string date;
public T property;
}
The generic type also contains a date, attribute (string), that should be validated against a valid date, so I wrote this function to do this:
public class ValidHistoryDateAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return true;
var v = (List<MyType<object>>)value;
bool valid = true;
foreach (var f in v)
{
if (!Regex.Match(f.Date, #"^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$").Success)
valid = false;
}
return valid;
}
}
The validation does not care about the property "property", but it should care about the string.
Unfortunately the cast fails:
var v = (List<MyType<object>>)value;
I mean: Of course it does, because "object" is not the real type. I want to use the validation attribute for all types and in the validation I actually do not even care about "property".
Any way to solve this in a nice way? I do not want to add a ValidHistoryDateAttribute for every possible type.
If I were to do this I would add a non-generic base type into your code:
public class ValidatableObject
{
public string date;
}
And then my class would be:
class MyType<T> : ValidatableObject
{
public T property;
}
Your validation code would then refer to the base class which makes things a lot simpler.
It looks like you are actually trying to cast something of type List<GenerericHistory<T>> which will run into Variance problems. If you are assuming you are using my base class the incoming item cannot easily be converted to List<ValidatableObject> - to see why consider that the actual list should only allow adding of GenerericHistory<T> (where T is a specific type) objects whereas a List<ValidatableObject> would allow adding of GenerericHistory<T> objects of any type. Thus the cast is not allowed.
If you were to change the list to an IEnumerable<GenerericHistory<T>> then you would be able to cast to IEnumerable<ValidatableObject>. The reason is that this time we have a readOnly object so all we are doing is getting out objects of type ValidatableObject and since know that the actual class will only ever return GenerericHistory<T> (for specific T) we also know it always returns of type ValidatableObject and thus this time the cast is allowed.
The last bit is based partly on speculation since your code seems to be inconsistent with regards to the use of List<T> in your code. I assume the validator is correct that a property on your validatable object is a list but obviously I have no idea if that List can be changed, etc.

Creating a class or interface for a complex generic type

I am trying to create an alias for a type of list of list of object. Specifically, I want to shorten all the typing I have to do for this type:
IReadOnlyList<IReadOnlyList<MyObject>>
My attempt is demonstrated here:
using System.Collections.Generic;
namespace MyApp
{
class Program
{
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return b.AsReadOnly();
}
}
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
static void Main(string[] args)
{
var collection = MyObject.GetCollection();
}
}
}
Unfortunately, this won't compile. There error is:
Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>'
to 'MyApp.Program.IMyCollection'.
An explicit conversion exists (are you missing a cast?)
OK, so I'm close. Perhaps explicitly casting? So I change the return statement in GetCollection to
return (IMyCollection)b.AsReadOnly();
That compiles, albeit with a resharper warning: Suspicious cast: there is no type in the solution which is inherited from both 'System.Collections.ObjectModel.ReadOnlyCollection>' and 'MyApp.Program.IMyCollection'
And at runtime, I get an invalid cast exception: Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyCollection1[System.Collections.Generic.IReadOnlyList1[MyApp.Program+MyObject]]' to type 'IMyCollection'.
OK, I can accept all that. I'm the last person to ask about stuff like covariance and contravariance and stuff like that. But surely there's a way to define and create an object with a short name to stand in for a really long named datatype.
How can I create a type with a really long name and cast to a type with a really short name?
UPDATE:
A co-worker suggested using a using statement.
using IMyCollection= System.Collections.Generic.IReadOnlyList<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>;
While that would work, it then becomes necessary to do that in every file that uses IMyCollection. Not exactly what I would consider a solution to my goal.
How badly do you want this?
You can manually implement your own wrapper class.
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
public class MyCollectionImpl : IMyCollection
{
private readonly IReadOnlyList<IReadOnlyList<MyObject>> _wrappedCollection;
public MyCollectionImpl(IReadOnlyList<IReadOnlyList<MyObject>> wrappedCollection)
{
_wrappedCollection = wrappedCollection;
}
public int Count
{
get
{
return _wrappedCollection.Count;
}
}
public IReadOnlyList<MyObject> this[int index]
{
get
{
return _wrappedCollection[index];
}
}
public IEnumerator<IReadOnlyList<MyObject>> GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
}
Then you simply create an instance of this:
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return new MyCollectionImpl(b.AsReadOnly());
}
}
This seems like a lot of extra work, but I would actually consider this a refactoring step.
I believe that the need to pass around types made up of complex set of generic parameters, is actually a bad smell in your code.
Ask yourself, what are you actually using IMyCollection for? Would you be able to add some specialized methods to this interface to make it easier to use?
Once you've created your own MyCollectionImpl class you can slowly add a number of methods to your IMyCollection interface to simplify it's usage. At some point, you might even get to the stage where you can stop exposing the <IReadonlyList<IReadonlyList<MyObject>> interface.
This has nothing to do with covariance. IMyCollection inherits from IReadOnlyList<IReadOnlyList<MyObject>> so you can cast an instance of IMyCollection to IReadOnlyList<IReadOnlyList<MyObject>> but not the other way around.
If you wanna have some custom conversions then you can create a type instead with the short name you want and declare a conversion from IReadOnlyList<IReadOnlyList<MyObject>> to your type using operator overloading. This really seems unnecessary and unusual way to use operator overloading but it's the only way to do what you want to achieve.

Initialize Property of Generic Type

I have read multiple posts but haven't found an appropriate answer for my problem.
But there has to be one. So please be patient if this post really is an duplicate.
I try to initialize a Property of a generic type implementing a generic interface.
My interface looks basically like this:
public interface IMyInterface<TType> : IMyInterface
{
TType Value {get; set;}
// ... and some more ...
}
public interface IMyInterface
{
SetValue(string value);
}
I have multiple Classes implementing IMyInterface without knowing them
at the piece of code, where I need to set the value.
Is it possible to inizialize the "Value"-Property without using the Name of the property?
(Is there a "nice" way to do this?) - It isn't possible to use SetValue< TType >
void SetValue(object obj, string value)
{
// object obj implements IMyInterface<???>
PropertyInfo valueInfo = typeof(obj).GetType().GetProperty("Value")
valueInfo.SetValue(obj, Activator.CreateInstance(valueInfo.PropertyType))
((IMyInterface)obj).SetValue(value);
}
Thanks in advance.
EDIT: - removed -
EDIT 2:
This structure is given:
public Interface IGeneric<TType> : INonGeneric
{
TType Value2 {get;}
}
public Interface INonGeneric
{
object Value1 {get;}
}
using "Value1" from reflection is really easy:
INonGeneric myObject = (INonGeneric)givenObject;
doSomething(myObject.Value1)
if i need to access "Value2" it isn't that easy. As one can see in my first example I had to use the following construct which not seems to be the best way to access "Value2", because the properties name is hardcoded.
PropertyInfo valueInfo = givenObject.GetType().GetProperty("Value2");
object value = (object)valueInfo.GetValue(givenObject);
Is there any better solution?
If i got you right you have and instance that implements IGeneric, and you want to access the property Value2 (which has a generic return type).
The thing is, Generics are for compile time type safety. You cannot cast your object to IGeneric<...> if you don't know the type parameter. So why do you want to use Generics anyway if you don't know the type parameter?
There is a solution for this "problem", it is the same as IEnumerable and IEnumerable< T> uses. it can look something like this:
public interface INonGeneric
{
object Value {get; }
}
public interface IGeneric<T>
{
T Value { get; }
}
public class Magic : INonGeneric, IGeneric<string>
{
object INonGeneric.Value { get { return this.Value; } }
public string Value { get { return "test"; } }
}
You can now use cast the Object to INonGeneric if you don't use the type parameter, or use the Generic implementation if you know the type parameter at compile time.
But if you want to access a property of a generic type (you have no control over) without knowing the type parameter you will not get around either reflection or dynamic.
The dynamic solution can look like this:
dynamic generic = givenObject;
object value2 = generic.Value2;

Pass Interface Type As Parameter

I already know that you can pass an interface as a parameter to a method. This allows you to specify only the relevant members of an object required by a method. What I would like to do is to be able to pass an interface type as a parameter.
Say I declared several interfaces, which were implemented un-evenly across a range of objects that all form a single list/collection. Could I write a helper method which would take both an object from the list and an interface type as a parameter, and check if the object implements the interface? The following code is obviously rubbish, but it illustrates the sort of thing I want to do:
private bool CheckType(object o, interface intrfce)
{
try
{
object x = (object)(intrfce)o;
return true;
}
catch (InvalidCastException e)
{
return false
}
}
At the moment I'm simply planning on setting up an enum for the interfaces, and requiring all classes to expose an array/list of interfaces they implement. I can then just check the enum list to see what interfaces they have that are relevant (I'm only interested in the interfaces I have created - I'm not after returning IEnumerable or ICloneable etc.) Or I could write helper methods for each interface. I was just wondering if there was a more elegant way of doing it?
You can do it using generics:
private bool CheckType<T>(object o) {
return o is T;
}
You call it like this:
foreach (object o in myList) {
if (CheckType<MyInterface>(o)) {
... // Do something
}
}
Considering how easy it is to do, you might as well do it in the conditional itself.
Finally, if you wish to process only objects implementing a particular interface in a mixed list, you could do it with LINQ's OfType method, like this:
foreach (MyInterface o in myList.OfType<MyInterface>()) {
...
}
You can do something like:
private bool CheckType(object o, params Type[] types)
{
//you can optionally check, that types are interfaces
//and throw exceptions if non-interface type was passed
if(types.Any(type => !type.IsInterface))
throw new Exception("Expected types to have only interface definitions");
return types.All(type => type.IsAssignableFrom(o.GetType()));
}
CheckType(new List<int>(), typeof(IEnumerable), typeof(IList)); //returns true
CheckType(0, typeof(IEnumerable)); //return false
To check a sequence of objects, you can use something along:
private bool CheckAllType(IEnumerable<object> items, params Type[] types)
{
return items.All(item => CheckType(item, types));
}

Base Class Enum Value from Derived Class?

Is it possible to get the enum value of a base class, from a derived class, without using reflection ?
The code below using Reflection, which seems a bit of overkill to get a base class field value from an object instance.
using System;
namespace Seans
{
public class BaseClass
{
public enum eEnum{a, b, c}
}
class Program
{
static void Main(string[] args)
{
DerivedClassA newObject = new DerivedClassA();
TraverseTheObjectHierachyForTheTaskListEnum(newObject.GetType());
Console.ReadLine();
}
public static Type GetTaskListType(Type type)
{
// Handle the cases where our enums are defined in the base class
return TraverseTheObjectHierachyForTheTaskListEnum(type);
}
private static Type TraverseTheObjectHierachyForTheTaskListEnum(Type type)
{
foreach (Type nestedType in type.GetNestedTypes())
{
if (nestedType.IsEnum)
{
// Enum Name, now you can get the enum values...
Console.WriteLine(nestedType.FullName);
return nestedType;
}
}
if (type.BaseType != null)
{
return TraverseTheObjectHierachyForTheTaskListEnum(type.BaseType);
}
return null;
}
}
}
So, not quite clear on exactly what you're looking for since there are really no fields in BaseClass, just the enum type definition. Either of these:
Enum.GetValues(typeof(BaseClass.eEnum));
or
Enum.GetValues(typeof(DerivedClassA.eEnum));
will give you the values of the enumeration. If you don't know the name of the enumeration at compile time, then reflection is the only way to go.
Your above code does not get a field value, but rather the type objects of all nested types.
The recursion in the method TraverseTheObjectHierachyForTheTaskListEnum is necessary, beacuse type.GetNestedTypes() will only return the types of the actual type provicded (that is DerivedClassA), but not of any types nested in its base classes.
You can easily verify this behaviour by stepping through your code with the debugger. You won't get any nested types for DerivedClassA, but for the base class type.GetNestedTypes() will return the enum.

Categories