I have written a function which will take a generic IEnumerable and map these objects (if possible) to objects I want to use for an algorithm. I don't have a lot of experience with generic objects or IEnumerables, so I wanted to ask for some advice.
I have written this code:
public static IEnumerable<OtherObject> MyObjectToOtherObject<T>(IEnumerable<T> objects)
{
if (objects.GetType() == typeof(MyObject))
{
var data = (IEnumerable<MyObject>)objects;
return data.Select(x => new OtherObject() { // Map the attributes });
}
else
return null;
}
This doesn't work in my code, since it returns null even though the input list is of the type MyObject. I just can't figure out how to cast my IEnumerable<T> to IEnumerable<MyObject>. Is there something I'm doing wrong?
Thanks in advance!
I'm sorry for all the confusion. I have asked this the wrong way. Alex has helped me enough, thank you!
this is wrong.
objects.GetType() == typeof(MyObject)
Correct:
objects.GetType() == typeof(IEnumerable<T>)
If you need to compare type of nested items:
objects.GetType().GetGenericArguments()[0] == typeof(MyObject)
typeof(T) == typeof(MyObject)
If you are checking if the type can be casted to another type:
objects.GetType().GetGenericArguments()[0].IsAssignableFrom(typeof(MyObject))
or just as
typeof(T).IsAssignableFrom(typeof(MyObject))
Doesn't look like you need a generic method, if you always know the source and destination types, you can do this:
public static IEnumerable<DestObject> ObjectToObject1(IEnumerable<SourceObject> objects)
{
return data.Select(x => new DestObject() { // Map the attributes });
}
I think what you're trying to do is build a generic mapping method which can map any give T to your concrete class Object1. You need to provide a mapping function which does the mapping.
Say you have this (overly contrived) example:
public class SourceObject
{
public string AString{get;set;}
}
public class DestObject
{
public string TheProperty{get;set;}
}
And you start with an IEnumerable<SourceObject> your method would need to take the list, and a Func<SourceObject,DestObject> to do the mapping
var input = new List<SourceObject>(){
new SourceObject{AString="Str1"},
new SourceObject{AString="Str2"}
};
var result = MyObjectToOtherObject(input, x => new DestObject{TheProperty = x.AString});
This is accomplished like so:
public static IEnumerable<DestObject> MyObjectToOtherObject<T>(IEnumerable<T> objects, Func<T,DestObject> mapping)
{
return data.Select(mapping);
}
As you can see, the separate method is more-or-less useless at this point. It's exactly what Select does.
objects will never be of type MyObject, therefore
(objects.GetType() == typeof(MyObject))
will always return false because object is some generic collection (IEnumerable<T>).
you could try using
typeof(T) == typeof(MyObject)
Related
I have a generic interface that requires a read and key method. I want to use reflection to get an instance of each implementation.
Once I have a the implementation, I want to get it's key and store the key and the instance in a dictionary.
Eventually, I would have a method where I pass in a key and byte[], it would look the key up in the dictionary and use the instance that it retrieves to read the byte[] and return an object.
I hope this is understandable, if not I can answer questions in the comments.
This example only has int and string, but I'll have many more types in my real implementation.
The Goal
To have a dictionary with 2 entries stored as such:
43, IRead<int> new Reader()
61, IRead<string> new Reader()
public interface IRead<T>
{
T Read(bool[] binary);
int Key( T type );
}
public class Reader : IRead<int>, IRead<string>
{
int IRead<int>.Read( byte[] binary )
{
// does stuff
returns 4;
}
public int Key( int type ) { return 43; }
string IRead<string>.Read( byte[] binary )
{
// does stuff
returns "example";
}
public int Key( string type ) { return 61; }
static StreamProcessor( )
{
// Here I want to get the definitions
}
}
Please, when you ask a question, post code that compiles. It makes life easier for everyone (perhaps your answer is because the pseudocode you wrote is wrong?)
In any case, this will get all types which implement IRead<>:
var types = GetType().Assembly.GetTypes()
.Select(t => new
{
Type = t,
MatchingInterfaces = t.GetInterfaces()
.Where(i => i.GetGenericTypeDefinition() == typeof(IRead<>))
})
.Where(t => t.MatchingInterfaces.Any())
Your pre-requisite of returning the key doesn't make that much sense. You can't find all instances of IRead<>. And you need an instance to give you a key.
For example, what would your dictionary look like if you had this code:
var readerOne = new Reader();
var readerTwo = new Reader();
Which instance goes into the dictionary?
The closest you can get is to:
Pass the method a list of objects and return the key of those instances
Create a dummy instance of each type to get the key
Make the key method static, and not part of the interface.
I suggest breaking this up because there are a few different things you're trying to do - some are clear, some aren't.
First you want to get types that implement IReader:
public IEnumerable<Type> GetTypes<TAssignableFrom>()
{
return this.GetType().Assembly.GetTypes()
.Where(type => type.IsAssignableFrom(typeof (TAssignableFrom)));
}
What do you want to do with those types? If you want to create an instance of each type then either they need to have parameterless constructors or otherwise identical constructors, or you'd need to be using some dependency injection container.
Let's say that they're going to have parameterless constructors. We can update the above to
public IEnumerable<Type> GetTypes<TAssignableFrom>()
{
return this.GetType().Assembly.GetTypes()
.Where(type => type.IsAssignableFrom(typeof (TAssignableFrom))
&& type.GetConstructor(Type.EmptyTypes) != null
);
}
Now you've got a bunch of types that you can instantiate.
From there it gets pretty fuzzy. What will you do with those types? It's not much use to put them into a dictionary because they are all different types.
I have a class which uses generic properties. For example:
class Person
{
public MyGenericProperty<string> Field1
{
get { return field1; }
set { field1 = value; }
}
private MyGenericProperty<string> field1= new MyInheritedGenericProperty<string>("Alan1");
}
I want to use this class with reflection at another class and i have a method like that
public void DoSomethingWithProperty(object sourceobject)
{
foreach (var aProperty in sourceobject.GetType().GetProperties())
{
*if(aProperty.PropertyType == typeof(MyGenericProperty<>))*
{
*var obj = (MyGenericProperty<>)aProperty.GetValue(sourceobject, null);*
}
}
return null;
}
I have two problem
1- How can do type check of generic property. In that example code of if(aProperty.PropertyType == typeof(MyGenericProperty<>)) does not work.
2- T of MyGenericProperty could be any class and how can cast MyGenericProperty class without knowing T by reflection as
var obj = (MyGenericProperty<>)aProperty.GetValue(sourceobject, null);
Thank for helps.
Firstly, it's important to understand that you don't have a "generic property" - there's no such thing. You have a property whose type is a generic type... and that's not the same thing. (Compare that with a generic type or a generic method, each of which is genuinely generic in terms of introducing new type parameters.)
You can test it using this code:
if (aProperty.PropertyType.IsGenericType &&
aProperty.GetGenericTypeDefinition() == typeof(MyGenericProperty<>))
But as for the casting - it depends on what you want to do with the value afterwards. You may want to declare a non-generic base type of MyGenericProperty<> containing all the members which don't depend on the type parameter. I'd typically give that the same name as the generic type (e.g. MyGenericProperty) just without giving it type parameters. Then if you only need one of those members, you can use:
if (aProperty.PropertyType.IsGenericType &&
aProperty.GetGenericTypeDefinition() == typeof(MyGenericProperty<>))
{
var value = (MyGenericProperty) aProperty.GetValue(sourceObject, null);
// Use value
}
But then in that case you could use Type.IsAssignableFrom anyway:
if (typeof(MyGenericProperty).IsAssignableFrom(aProperty.PropertyType))
{
var value = (MyGenericProperty) aProperty.GetValue(sourceObject, null);
// Use value
}
If these hints don't help you, please give more details of what you're trying to do.
Is it possible to check if the list contains an object of given (but dynamic) type, derrived from same basic abstract class?
The main problem is not about the list, but about comparing types itself.
In single variables and static variables, it's easy:
if(someVariable is int)
Checking the list with static type is also easy, like:
SomeList.OfType<int>().Any()
or
(from _Object in SomeList.OfType<int> where _Object is int select _Object).Count() == 0
but I cant't handle it if the type I want to check is dynamic, f.e. passed as method parameter:
abstract class BasicClass;
class DerivativeOne : BasicClass { }
class DerivativeTwo : BasicClass { }
// in main:
List<BasicClass> _List = new List<BasicClass>();
DerivativeOne a = new DerivativeOne();
DerivativeTwo b = new DerivativeTwo();
DerivativeOne c = new DerivativeOne();
if(!CheckIfTypeExistsInList(a, _List)
{
_List.Add(a);
}
if(!CheckIfTypeExistsInList(b, _List)
{
_List.Add(b);
}
if(!CheckIfTypeExistsInList(c, _List)
{
_List.Add(c); // this is what I don't want to happen,
// because I already have one object of type DerivativeOne in my list.
}
// the function:
bool CheckIfTypeExistsInList(BasicClass pObject, List<BasicClass> pList)
{
/// few attempts:
pList.OfType<(pObject.GetType()>().Any(); // attempt one, error
return (from _Object in SomeList.OfType<(pObject.GetType())> where _Object is int select _Object).Count() == 0; // attempt two, error
}
PS. I am aware that the code doesn't look neat, but I tried to show just the problem itself, skipping extra logic and stuff.
PS2. I am aware that the solution to the problem would be just to put some attribute to BasicClass and make each derivative to have unique value of the attribute, but still - I'm not looking for another route to solve the problem, I'm just interested if it's possible to do it "this" way.
When the type is known only at runtime, you cannot use it in a generic without using reflection. However, your task is simpler than that - you can use type equality to achieve the results that you want:
Type targetType = pObject.GetType();
if (SomeList.Any(o => targetType.Equals(o.GetType()))) {
...
}
I have throughout my application many methods where I load collections. They all (actually most with a couple of differentials) follow the following pattern:
public BaseCollection<ObjectType1> LoadObjectType1(EventHandler handleEvent)
{
var myQuery = ObjectType1.Load(MyServiceContext);
return new DataManager<ObjectType1>().GetData(myQuery , handleEvent, MyServiceContextt);
}
public BaseCollection<ObjectType2> LoadObjectType2(EventHandler handleEvent)
{
var myQuery = ObjectType2.Load(MyServiceContext);
return new DataManager<ObjectType2>().GetData(myQuery , handleEvent, MyServiceContextt);
}
public BaseCollection<ObjectType3> LoadObjectType3(EventHandler handleEvent)
{
var query = ObjectType3.Load(MyServiceContext);
return new DataManager<ObjectType3>().GetData(query, handleEvent, MyServiceContextt);
}
Where ObjectType# are my business objects, e.g. Employee, Department, etc.
I would like to convert these to harness Generics.
Any advice will be greatly appreciated.
You can always create version of these functions that take a generic argument themselves. However, since there is no argument that can allow the compiler to infer the type of the generic argument, you will always have to supply it in the call.
The main issue, is that you're using a static Load method that is implemented on each object type. You would have to pass this in to the call as a delegate:
public BaseCollection<T> Load<T>(EventHandler handleEvent, Func<QueryType> querySelector)
{
var myQuery = querySelector(MyServiceContext);
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContext);
}
When calling these version, you would have to specify the type T, as well as pass in a delegate that will return the query object you use to load your data (since it's type specific):
LoadDepositionSampleTypeItemSource<Department>( handler, Department.Load );
EDIT: So, now that you've updated your question I think I understand it a bit better. There's no reason you can't collapse the different methods down to a single overload. If you can refactor the implementation so that the query is not retrieved from the object type, you may be able to improve and consolidate things further. A factory pattern may make things cleaner and more maintainable:
public BaseCollection<T> Load<T>(EventHandler handleEvent)
{
var myQuery = QueryManager.GetQuery<T>(MyServiceContext);
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContext);
}
Do you mean you want the methods to be generic? Something like this?
public BaseCollection<T> LoadObject<T>(EventHandler handleEvent)
{
var myQuery = BusinessUtil.Load<T>(MyServiceContext);
return new DataManager<T>().GetData(myQuery, handleEvent, MyServiceContext);
}
Of course, the problem with this is that you can’t easily call the separate static .Load() methods you already have. You will have to declare a single static generic .Load() method, which can return objects of any of your business types. Something like this maybe:
public static class BusinessUtil
{
public static T Load<T>(ServiceContext context)
{
if (typeof(T) == typeof(Object1))
return (T) Object1.Load(context);
if (typeof(T) == typeof(Object2))
return (T) Object2.Load(context);
// ... etc.
}
}
Alternatively, you can require an extra parameter on LoadObject<T> that specifies how to create such an object:
public BaseCollection<T> LoadObject<T>(EventHandler handleEvent,
Func<ServiceContext, T> generator)
{
var myQuery = generator(MyServiceContext);
return new DataManager<T>().GetData(myQuery, handleEvent, MyServiceContext);
}
// ...
var obj = LoadObject(handleEvent, Object1.Load);
This is assuming that myQuery needs to be of type T, which unfortunately the code in your question doesn’t reveal. If it needs to be a different type, maybe some sort of Query<T>?, then you will need to change the T inside the Func<> (and the return type of BusinessUtil.Load) to that too.
You could use Reflection:
public BaseCollection<T> LoadGeneric<T>(EventHandler handleEvent)
{
var myQuery = (YourQueryType)typeof(T)
.GetMethod("Load")
.Invoke(null, new object[] { MyServiceContext });
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContextt);
}
But I think refactoring the code (maybe using single static method as Timwi suggested) would be a better choice.
I have asked this question about using the a Linq method that returns one object (First, Min, Max, etc) from of a generic collection.
I now want to be able to use linq's Except() method and I am not sure how to do it. Perhaps the answer is just in front on me but think I need help.
I have a generic method that fills in missing dates for a corresponding descriptive field. This method is declared as below:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection, string datePropertyName, string descriptionPropertyName)
{
Type type = typeof(T);
PropertyInfo dateProperty = type.GetProperty(datePropertyName);
PropertyInfo descriptionProperty = type.GetProperty(descriptionPropertyName);
...
}
What I want to accomplish is this. datePropertyName is the name of the date property I will use to fill in my date gaps (adding default object instances for the dates not already present in the collection). If I were dealing with a non-generic class, I would do something like this:
foreach (string description in descriptions)
{
var missingDates = allDates.Except(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
...
}
But how can I do the same using the generic method FillInMissingDates with the dateProperty and descriptionProperty properties resolved in runtime?
I think the best way would be to define an interface with all of the properties that you want to use in your method. Have the classes that the method may be used in implement this interface. Then, use a generic method and constrain the generic type to derive from the interface.
This example may not do exactly what you want -- it fills in missing dates for items in the list matching a description, but hopefully it will give you the basic idea.
public interface ITransactable
{
string Description { get; }
DateTime? TransactionDate { get; }
}
public class CompletedTransaction : ITransactable
{
...
}
// note conversion to extension method
public static void FillInMissingDates<T>( this IEnumerable<T> collection,
string match,
DateTime defaultDate )
where T : ITransactable
{
foreach (var trans in collection.Where( t => t.Description = match ))
{
if (!trans.TransactionDate.HasValue)
{
trans.TransactionDate = defaultDate;
}
}
}
You'll need to Cast your enumeration to ITransactable before invoking (at least until C# 4.0 comes out).
var list = new List<CompletedTransaction>();
list.Cast<ITransactable>()
.FillInMissingDates("description",DateTime.MinValue);
Alternatively, you could investigate using Dynamic LINQ from the VS2008 Samples collection. This would allow you to specify the name of a property if it's not consistent between classes. You'd probably still need to use reflection to set the property, however.
You could try this approach:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection,
Func<T, DateTime> dateProperty, Func<T, string> descriptionProperty, string desc)
{
return collection.Except(collection
.Where(d => descriptionProperty(d) == desc))
.Select(d => dateProperty(d));
}
This allows you to do things like:
someCollection.FillInMissingDates(o => o.CreatedDate, o => o.Description, "matching");
Note that you don't necessarily need the Except() call, and just have:
.. Where(d => descriptionProperty(d) != desc)
foreach (string description in descriptions)
{
var missingDates = allDates.Except<YourClass>(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
}
In fact, almost all LINQ extension in C# have a generic possible value. (Except and Except)
If you're going to identify the property to be accessed by a string name, then you don't need to use generics. Their only purpose is static type safety. Just use reflection to access the property, and make the method work on a non-generic IEnumerable.
Getting Except result with multiple properties working with custom data class is not allowed.
You have to use it like this: (given in msdn 101 LINQ Samples)
public void Linq53()
{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var productOnlyFirstChars = productFirstChars.Except(customerFirstChars);
Console.WriteLine("First letters from Product names, but not from Customer names:");
foreach (var ch in productOnlyFirstChars)
{
Console.WriteLine(ch);
}
}
Having the key, you can handle your data accordingly :)