How to get first item from XmlSchema.Elements - c#

I have XmlSchema object. Which has Elements property. I need a first element from it. I cant figure how to get it not writing foreach/break (which would look stupid). Is there a nice way?
EDIT: the only way I found is : getenumerator/movenext/value;
EDIT2: one of the ways is to cast XmlSchema.Elements.Values (ICollection) to a meaningful type to use with Linq. The problem is that I cant find that type. The GetType gives me name: "System.Xml.Schema.XmlSchemaObjectTable+ValuesCollection"
I dont see this type in the ObjectExplorer and I cant cast to it..
Please answer if you have working solution rather than just throwing in whatever comes to your head. Thanks.

Use linq on the Names or Values of the elements, depending on what you need
E.g.,
var v = yourObject.Elements.Names.OfType<XmlQualifiedName>().FirstOrDefault();
var w = yourObject.Elements.Values.OfType<XmlSchemaElement>().FirstOrDefault();
===
Edited: Added OfType<> to get an ICollection<> instead of an ICollection so that it is possible to use FirstOrDefault
Note: I verified this solution on the example XmlSchema from http://msdn.microsoft.com/en-us/library/system.xml.schema.xmlschema%28v=vs.110%29.aspx, if your element names or values have a different type you'll need to change that in the OfType<>

Related

Remove an object from List of dynamic object

//Data is IList<ExpandoObject>
var result = (from dynamic item in Data
where item.id== "123"
select item).FirstOrDefault();
Want to achieve below feature but it is erroring out by saying remove not available for dynamic objects.
Data.Remove(result);
Let me know if any suggestions.
thanks
Error: remove not available for dynamic objects
base on Microsoft's docs, The Remove method of IList<T> accepts a parameter with the type of T:
ICollection<T>.Remove(T)
In your example, T is an ExpandoObject, so it means in the Remove method you should pass a parameter with the type of ExpandoObject but you didn't and you are passing a parameter with the type of dynamic. Therefore you facing this error
for resolving this you have two way:
1) Use explicit type instead of var:
ExpandoObject result = ...
2) cast the result when you are passing it to Remove:
Data.Remove((ExpandoObject) result)
I think with doing one of these ways, your problem will resolve. good luck.

How could I've known the cast to List<> makes sense?

For this code snippet below, which probably won't need an explanation to the persons who can answer my question:
protected readonly List<TEntity> Records; //Within the class declared.
protected virtual void ReadFile()
{
//So the file exists, is not null and not whitespace only
var serializer = new XmlSerializer(Records.GetType());
using (var reader = new StringReader(contents))
{
var records = (List<TEntity>)serializer.Deserialize(reader);
Records.Clear();
Records.AddRange(records);
}
}
It's about the line:
var records = (List<TEntity>)serializer.Deserialize(reader);
(1) How could I've known (deduced) that this cast was possible? I looked up that the Deserialize() methods returns the type "object". So that's can't be the hint. (Edit: I mean during coding/design time. Not compiling afterwards for trial and error. So think goal-wise: goal = store xml data into a list<>. Is it possible through a simple cast (yes) and how could I have known in advance?).
(2) How could I've / can I deduce(d) how variable "records" would end up? For example, what shouldn't make me think that only a single entry is written to the list and that single index holds all of the XML content? (as opposed to keeping a nice structure whilst writing it to the list)
The final goal of my question is to understand when such a cast is needed and especially how the actual cast makes sense. I'm wiling to put in effort in it with practice and experimentations. But I don't know how to think.
a) I"m a beginner, though learning fast i.m.o.
b) I Have read and understood implicit/explicit casting and understood that it's based on range, as opposed to data size. But those tutorials restrict to built in basic types like int, float, decimal (you name it). Now this problem domain (casting) I would like to move to a higher level.
The cast
var records = (List<TEntity>)serializer.Deserialize(reader);
works because of
new XmlSerializer(Records.GetType());
The cast from object to anything will always compile but yield a runtime exception when the types don't match.
The serializer knows about the root type from its constructor and will create a result of that type. If the XML doesn't match that, it will throw an error. You cannot deserialze a single TEntity with this, only a List<> with 0 or more elements.
You can verify it easily:
object temp = serializer.Deserialize(reader);
// print or inspect temp.GetType() here
var records = (List<TEntity>)temp;
Note that if XmlSerialzier had been designed as a generic type then the cast would not have been necessary:
var serializer = new XmlSerializerGeneric<List<TEntity>>();
var records = serializer.Deserialize(reader);
But it wasn't, it uses the older way of 'dynamic typing' through the System.Object class.
It would be much obvious if instead of this
var serializer = new XmlSerializer(Records.GetType());
you used this
var serializer = new XmlSerializer(typeof(List<TEntity>));
The rule is simple. What ever type you pass to the XmlSerializer constructor, you can safely cast the Deserialize result to that type.
The cast is needed because XmlSerializer (as well as Enum and many other framework classes) exists from a long time before the generics were added, so returning an object is the only choice it had. And it must remain this way because of backward compatibility (to not break the existing code you have written).
How could I've known (deduced) that this cast was possible?
One way is to use the debugger. Put a breakpoint on the Records.Clear(); line just after records is set. Then in either the Watch window or the Locals window, take a look at the type of the records variable. It might say something like this:
object { List<TEntity> }
records is a List<TEntity> but it's being passed as an object because the call to serializer.Deserialize(reader) returns an object. And if you didn't declare an implicit conversion from object to List<TEntity>, you have to use an explicit conversion.
I recommend against implicit conversions for all but the most obvious cases.
(1) How could I've known (deduced) that this cast was possible?
It all began here,
protected readonly List<TEntity> Records;
You don't have to deduce but you already know you are reading file contents from a file which has some XML with some sort of structure and since you are using a list you know upfront that there are going to be mulitple list items
I looked up that the Deserialize() methods returns the type
"object". So that's can't be the hint.
object class is not used directly (So basically that is a hint that you have to cast) and it must be casted to some type (in this case List<TEntity>) before it could be used.
(2) How could I've / can I deduce(d) how variable "records" would end
up?
Lets say I want to create list of persons, I would know I would keep some structure for example,
I have following XML
<persons>
<person>
<name>Chuck Norris</name>
<age>137</age>
</person>
<person>
<name>Donald Trump</name>
<age>19</age>
</person>
<persons>
You know you want to get the records of person your list would be declare like this, List<Person>. You know Deserialize() method returns object and you would want to read persons data, you would cast that object into List<Person>. So basically what I am trying to say is that both the question you asked are based on the assumption and choices made at the design time of you application.

Can I get the item type from a BindingSource?

I would like to get the Type of item that a BindingSource is hooked up to or configured for. The BindingSource.DataSource property can be set to an object, list, or type. If it is a Type, it obviously does not have a bound item yet, but I would still like to get the Type. For a List, I need the item Type, not the list type.
I currently have a custom list type for business objects that implement an IListItemType interface, that I created to solve this problem a while back. I would now like to get this working in a more generic fashion so that it will work with any list.
I've looked through the API docs for for a good way to do this, but so far I have not had any luck. Am I missing something or is this just something I can not or should not be doing?
I recently ran across the ListBindingHelper class in the framework that has everything I was looking for:
System.Windows.Forms.ListBindingHelper.GetListItemType()
Returns the type of an item contained in a list or collection.
ListBindingHelper.GetListItemProperties()
Returns a PropertyDescriptorCollection that describes the properties of the items contained in the list.
There is no completely generic way to get the "type" of the list. The most common method is to examine the first item, but this can be misleading as you can have objects that are of a more specific type in a collection that is less specific (in other words, the collection might be a List<object>, but the first item might be a string, leading you to guess that it's a List<string>). If you're confident that all of the elements will be the same type (meaning none are more specific than the generic type of the collection or than any of the other objects), then examining the first item is the easiest.
Apart from that, you could examine the list's actual type using GetType and check its interfaces. Chances are that any collection that's strongly typed is going to implement IEnumerable<T>, so you can iterate over its interfaces looking for IEnumerable that's generic, then look at its generic type arguments. It's (more than) a little hokey, but it should work.
TL;DR Version
Try this. Assuming you're using .NET 3.5 and have the list stored in a variable called list:
var listType = list.GetType().GetInterfaces()
.Where(t => t.Name == "IEnumerable" && t.IsGenericType)
.Select(t => t.GetGenericArguments()[0]).FirstOrDefault();
As long as the list implements IEnumerable<T>, this will give you T. If it doesn't, chances are the list type is object anyway.
It's been quite a while since this answer has been on board but just in case anybody is still looking for the answer...
I ran into a similar problem. My scenario was that BindingSource.DataSource would always be bound to an IEnumerable BUT there may not be any items in the list. It turns out that BindingSource has a private instance member called "itemType". This field does just what you're looking for: it shows the element type of a list if the BindingSource is bound to a list, or it shows the type of the object that the BindingSource is bound to, if there is no list.
To access the field value, I used some hacky reflection:
FieldInfo fi =
typeof(BindingSource)
.GetField("itemType", BindingFlags.NonPublic | BindingFlags.Instance);
Type myElementType = fi.GetValue(DataBinder.RestrictedDataBinding) as Type;
Without doing much research, I kind of assume that what it's doing is showing the element type of the innerList, which is why it doesn't matter if the DataSource is a list type or not. Also, I assume this field would accurately show the element type of any kind of list that is supported by the BindingSource (including IQueryables, etc.).
WARNING: I have NOT tested this field much so I don't know if there are cases that would make it not read the correct element type. For example, does the field always get accurately updated when the BindingSource's DataSource property is reset? What if the DataSource property is reset to a list that has a different elementType? In my case, these exceptions and others don't apply but you might want to test them.
Lastly, using reflection to hack into private fields breaks all kinds of oop principles. Keep that in mind. Also, keep in mind that there very well might be a good reason why the itemType field was hidden. If you need to investigate further, the code for the BindingSource class is publicly available.

ICollection cast problem

Is there any solution to solve the problem with this cast example? I need to add a new element to the collection, so I have to solve it.
IEnumerable enumerable;
IEnumerable enumerable2;
enumerable = new ObservableCollection<Something>();
enumerable2 = new ObservableCollection<Object>();
ICollection<Object> try = (ICollection<Object>)enumerable; //Don’t work
ICollection<Object> try2 = (ICollection<Object>)enumerable2; //Work
Check out covariance and contravariance with generic parameters in C# 4. It might provide you with more information for future when faced with such problems.
I'm not sure 100% that this is what you mean, but have you tried this:
IEnumerable<Object> try3 = enumerable.Cast<Object>();
Ok, it didn't work, how about dynamic typing:
dynamic var = new Something();
dynamic try1 = enumerable;
try1.Add(var);
If all you know is object, then the non-generic interfaces are your friend:
IList list = (IList)foo;
list.Add(yourItem);
However! Not all enumerable items are lists, so not all can be added in this way. IList underpins a lot of data-binding, so is a good bet.
"try" is a reserved word in C#. Have you tried another variable name? or you could use #try if you need to use the "try" variable name.
You can iterate through the something collection and insert the elements into the object one.
If you have control over the relevant code, it is perhaps time to rethink the design a little. One often tries to use the most restricted interface possible that can still achieve the desired result. It seems in this case that IEnumerable cannot achieve that result, if one of the things you want to do is to add new items. Changing to a more appropriate type might be a better solution than having to cast the collection.
Use the Cast extension combined with a ToList.
IEnumerable ie1 = new ObservableCollection<string>();
ICollection<object> ic1 = (ICollection<object>)ie1.Cast<object>().ToList();
Or iterate through manually.
Dynamic typing works (Only one bad thing, that I have to link windows.csharp and system.core dlls, which are ~1MB, so it's not the best for a silverlight app, but It's the best solution, which I know now.)

var keyword isn't inferring the type of RepeaterItem, why is that?

This is a quick one. I have the following code:
foreach (var item in myRepeater.Items)
{
MyViewModelItem x = new MyViewModelItem();
MapToEntity(x, item);
myList.Add(report);
}
void MapToEntity(object entity, Control control);
I expected this code to compile with no problems. It didn't, however.
It resulted in a compile time error saying that the method "MapToEntity" has some invalid arguments. The compiler failed to infer the type of the RepeaterItem, it recognizes it as a plain System.Object.
Why is this happening? Am I missing something?
Ps: I fixed the code by deleting the var keyword and explicitly defining the type of the item "RepeaterItem".
RepeaterItemCollection does not implement IEnumerable<RepeaterItem> just plain IEnumerable. Thus, it's impossible for the compiler in infer the type.
First, your code sample shows that you are using a variable named "item" in the foreach statement and then declaring one of another type below it.
Second the reason you probably seeing it as type Object is that myRepeater.Items is probably a general collection and not a specifically typed one so it would return of type Object. You can specifically state of what type in the ForEach loop and it will return objects of that type if any exist.
A possible solution would be to do myRepeater.Items.OfType() and then you could use the var keyword.
As Anton said, the Items only implements IEnumerable which is why it cannot infer the type.
One thing that you may find useful though is the Cast method.
myRepeater.Items.Cast<RepeaterItem>()
Whilst your example is simple enough for this to not really be needed it may help for more complex examples where you need a typed enumerable.

Categories

Resources