I have an hierarchy of classes that I fetch from database by LINQ to SQL controller and the display that big class as needed.Let me explain:
BigProduct
IEnumerable<Review>
//...some generic types
Review
IEnumerable<Comment>
//...some generic types
Comment
//...some generic types
So in my controller I fetch big product and pass it to main view, then pass reviews in foreach to partial views and in each of these partial views I have another foreach that should list all comments as partial view.
The types are defined clear as Ienumerable in classes and this dll worked fine with web forms,now when I hover my mouse over Comment in foreach loop in razor it says it's EntitySet instead of IEnumerable and I get "null exception: acessed context after disposed", that was the reason I am passing it as IEnumerable in first place as I fetch everything in one place. What could be the reason for such behaviour? I didn't change anything in this dll that used to work fine with webforms.
UPDATE: As I mentioned it worked fine with WebForms, I am calling .ToList() to get IEnumerable from IQueryable in when selecting data!
Just because you declare it as IEnumerable<T>, that doesn't change the execution-time type. So when you pass it over to your view, the view would know at compile-time that it's IEnumerable<T> but when you hover over it when debugging, you'll see the actual type. (It's not clear at what point you were hovering over Comment in the razor view, but I strongly suspect it's in the middle of a debugging session.)
If you want to take a copy of the data so that you can dispose the context, just call ToList() and return the result - that will be a List<T> instead.
Note that this compile-time/execution-time difference has nothing to do with LINQ or MVC really. You can see the same thing extremely easily without anything complicated:
object value = "hello";
The compile-time type of value is object, which will stop you calling Substring etc on it. But if you hover over value in a debugging session (or look at it in the Watch or Local window) you'll see that the execution-time type is still string.
EDIT: From your edit:
I am calling .ToList() to get IEnumerable from IQueryable in when selecting data!
I'd really like to see that code, because I don't believe you're simply using something like:
return query.ToList();
If you're returning the result of calling ToList(), that won't be an EntitySet.
When you return a reference to an interface type, like IEnumerable<T>, the reference still points to the object whose run-time type implements the interface. More generally, whenever you refer to an object through an interface that it implements, or through a base class in its inheritance chain, you're still referring to an instance of the object's most-derived type.
For example:
object o1 = new object();
object o2 = "I am a string.";
object o3 = 42;
Console.WriteLine(o1.GetType());
Console.WriteLine(o2.GetType());
Console.WriteLine(o3.GetType());
IComparable ic1 = "I am a string.";
IComparable ic2 = 42;
Console.WriteLine(ic1.GetType());
Console.WriteLine(ic2.GetType());
Output:
System.Object
System.String
System.Int32
System.String
System.Int32
If you want to copy the data to another object that also implements IEnumerable<T>, you need to write some code to do that. As others have suggested, calling ToList() is an easy way to achieve this.
Related
I have a dynamic type in C# (Content, a type that inherits DynamicObject). It wraps an inner JSON object containing the data. In TryGetMember I return the requested properties from this inner JSON object. This works just fine in case of simple types (e.g. an int or string property), because .Net converts those values correctly.
But I want to use properties with more complex types:
dynamic content = Content.Load(id);
IEnumerable<Book> bookList = content.Books;
The problem is that in TryGetMember of my class I have no way to know the type that I should convert to (in this case the IEnumerable Book), because binder.ReturnType is always Object. According to this article, this is the normal behavior:
Determining the expected type of a DynamicObject member access
But I find this very hard to believe: how is it possible that the API does not let me know the target type? This way I will have to force developers to use the method syntax to specify the type explicitely:
IEnumerable<Books> bookList = content.Books<IEnumerable<Book>>();
...which is ugly and weird.
You could store Type data alongside the JSON serialized data, but that seems like a rather inefficient method of accomplishing what you're trying to do. If your content isn't truely dynamic (e.g., the content changes, but the basic schema of the object is the same), you could just have precompiled classes for each JSON object type, and serialize the JSON into that class once you receive the data. This way, all of the type data would already be recognized by the compiler at runtime.
It turns out that this is not possible indeed. I ended up creating an extension method (defined in two forms: for dynamic collections and JArrays). That way I can at least get a collection of my Content class and all of the following solutions work:
One line, but a bit long
var members = ((IEnumerable<dynamic>)group.Members).ToContentEnumerable();
Separate lines
IEnumerable<dynamic> members = adminGroup.Members;
foreach (dynamic member in members.ToContentEnumerable())
{
//...
}
Using the method call syntax of the extension method (a bit unusual).
var members = ContentExtensions.ToContentEnumerable(group.Members);
So, I have my own mapper (NOT AutoMapper) which maps models to each other. You give the model you'd like to map to, and with the Map method you push an object in. Beside of this I wrote the Extend method which functions as a override for the Map method to, for example, add properties which are not available in the object being mapped.
Problem:
The problem hereby is that my public Mapper<T> Extend(Func<T, T> func) method doesn't like the different types.
Possible solutions:
There are 2 solutions I'm thinking of:
Ignore the error and map the value within my Extend method. Which isn't possible as far as I know due to the expression being executed immediately.
Create a LINQ method which maps the value for me. Eg; q => q.Ownership = obj.Ownerships.First().Map().
Question:
How can I resolve this error and achieve what I want?
I have a Helper Class, that i use to pass between the layers on my program. One of the features of this class, is that it returns if the bottom layer has had an error. Also it passes back through the layers the data associated with the routine (ie, returns a database table, string, integer etc..). Currently i add the data via a object type. and the callee routine needs to know what datatype is coming back.
My question is, is there a way to return the object, and also what type of data it is ? and how would i store the type descriptor?
currently this is how is it implemented:
This is an example of the lower level (for a db routine that didn't have a error):
return new MyHelper()
.AndAddObjectToReturn(rep)
.AndHasNoErrors();
and this bubbles up to the callee code which does this:
.....
if (contactidHelped.HaveNoErrors())
{
repContact contact = (repContact) contactidHelped.GetAttachedDataObject();
....
}
what i want to do is on the callee routine, is for it to be ignorant if the datatype and do code like this:
.....
if (contactidHelped.HaveNoErrors())
{
repContact contact = contactidHelped.GetAttachedDataObject();
....
}
so that the expected object is what it needs.
As far as I'm aware, you are not able to do it in a simple way. what I can think of to achieve a similar behavior is to use type constraint at your helper class.
Create a base Helper class (let's say MyHelper) which has a virtual GetAttachedDataObject returning object type, while deriving another class - MyHelper<T>, which has a method GetAttachedData<T> returning value of type T.
When you initialize/instantiate the helper, instantiate a strong typed MyHelper<T>. At the caller, you can cast your MyHelper to your desired MyHelper<T> upfront and call GetAttachedData instead of GetAttachedDataObject. of course, you could further tweak this to meet your needs.
but this is not ideal either - it still requires you to do casting at some point, though I believe it could reduce the needs of casting.
You can pass the GetAttachedDataObject() around by simply storing it as an object, for example
var attachedDataObject = contactidHelped.GetAttachedDataObject();
Then when you need to access a specific property or method for any given object just check the type like:
if (attachedDataObject is repContact) {
// your code here
}
However, I would suggest you check how Interfaces work, maybe it will be more suited to your needs.
I am having a lot of trouble with Reflection in C# at the moment. The app I am writing allows the user to modify the attributes of certain objects using a config file. I want to be able to save the object model (users project) to XML. The function below is called in the middle of a foreach loop, looping through a list of objects that contain all the other objects in the project within them. The idea is, that it works recursively to translate the object model into XML.
Dont worry about the call to "Unreal" that just modifes the name of the objects slightly if they contain certain words.
private void ReflectToXML(object anObject, XmlElement parentElement)
{
Type aType = anObject.GetType();
XmlElement anXmlElement = m_xml.CreateElement(Unreal(aType.Name));
parentElement.AppendChild(anXmlElement);
PropertyInfo[] pinfos = aType.GetProperties();
//loop through this objects public attributes
foreach (PropertyInfo aInfo in pinfos)
{
//if the attribute is a list
Type propertyType = aInfo.PropertyType;
if ((propertyType.IsGenericType)&&(propertyType.GetGenericTypeDefinition() == typeof(List<>)))
{
List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);
foreach (object aListObject in listObjects)
{
ReflectToXML(aListObject, anXmlElement);
}
}
//attribute is not a list
else
anXmlElement.SetAttribute(aInfo.Name, "");
}
}
If an object attributes are just strings then it should be writing them out as string attributes in the XML. If an objects attributes are lists, then it should recursively call "ReflectToXML" passing itself in as a parameter, thereby creating the nested structure I require that nicely reflect the object model in memory.
The problem I have is with the line
List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);
The cast doesn't work and it just returns null.
While debugging I changed the line to
object temp = aInfo.GetValue(anObject,null);
slapped a breakpoint on it to see what "GetValue" was returning. It returns a "Generic list of objects" Surely I should be able to cast that? The annoying thing is that temp becomes a generic list of objects but because i declared temp as a singular object, I can't loop through it because it has no Enumerator.
How can I loop through a list of objects when I only have it as a propertyInfo of a class?
I know at this point I will only be saving a list of empty strings out anyway, but thats fine. I would be happy to see the structure save out for now.
Thanks in advance
I'm assuming that the actual value is not a List<object> but is something like a List<string> or List<int> or some other type that isn't exactly object?
If so, then the reason that the cast is failing is because generic classes are neither co- nor contravariant.
In C# 4.0, however, you will be able to make the foreach loop work by casting to IEnumerable<object> because interfaces can be co/contravariant.
(Much) more information here: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Edit:
Thinking about it, you don't need generic variance here. List<T> implements the non-generic IEnumerable. This is all you need for the foreach loop to operate, and you only need the elements as type object so just cast it to an IEnumerable instead of List<object> and everything should work fine.
Generics and reflection don't mix well, especially for lists. I would strongly suggest using (non-generic) IList, or if that fails (some generic lists don't implement it), IEnumerable (since IEnumerable<T> : IEnumerable) and invoke the Add manually.
I feel your pain, really (I maintain an OSS serialization API).
In C# 3, you can't cast Lists<T> to other types of Lists<T> even when casting to something like List<Object>. It's explicitly not allowed even when casting to List.
In 4.0 variance changes a little with interfaces with the addition of the in and out keywords.
Here is a link to Eric Lippert explaining how and why this is the case.
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Couldn't you just cast them to objects with OfType()?
List<object> listObjects = anObject.OfType<object>().ToList();
Update:
If the requirement wasn't for a List<object>, this would also work and involve no duplication of the list items:
var enumerableObjects = anObject.OfType<object>();
Just I am maintaining a project.It has been written in C# 3.0.Some Implementations return collection as IQueryable.
like
List<BookData> data = new List<BookData>();
...
data.Add(new BookData { ID = "P001", BookTitle = "C# in Depth" });
data.Add(new BookData { ID = "P002", BookTitle = "F# in Depth" });
public IQueryable GetBooks()
{
return data.AsQueryable();
}
The code would have return the collection list. What is the special in returning them
as AsQueryable ?
Without using reflection or casting the returned object, the only methods that are available on the returned collection are those defined by the interface. This would be one way of restricting some types of access to the collection -- for instance, IQueryable doesn't have an add method. Unfortunately this isn't safe in the face of a "hostile" user of your code. If you truly need the collection to be inviolable, a better way is to return a read-only copy of the collection rather than the actual collection cast as a different interface.
Note that I'm assuming a List, as in your example, or some other class that actually implements IQueryable natively. In this case the source object is returned. If the underlying object doesn't implement IQueryable then an IQueryable is returned that proxies the calls to the underlying IEnumerable.
AsQueryable doesn't really do anything when invoked on a plain old collection like a List<T>, so the answer probably depends on another part of the codebase. For example, someone might have defined a GetBooks method to take an IQueryable<Book>, with the intent that the GetBooks method would perform any ordering or filtering in the database via a LINQ provider. But the code you're looking at constructs the set of books as a collection (a List<Book>), not a query. In order for the result to be passed the hypothetical GetBooks method, the collection has to be wrapped in an IQueryable<Book>, even though that wrapper is just going to delegate straight back to the LINQ to Objects methods (rather than translating the GetBooks operations to SQL queries).
Or perhaps the class you're looking at implements an interface where the method you're looking at is declared as returning IQueryable<Book> (for similar reasons to above), so your code is having to wrap the List<Book> to remain compatible with the interface signature.