I have a small problem with my Exchange Appointment. The idea is to sync a meeting from sharepoint calendar to the personal exchange calendar.
I have this StringList in my CalendarItem Class:
private StringList m_Category;
public StringList Category { get { return m_Category; } }
And there it should go:
Microsoft.Exchange.WebServices.Data.Appointment xApointment = new Appointment(m_Service)
xApointment.Categories = xItem.Category; //xItem = Instance of CalendarItem
In the Microsoft.Exchange.WebService.Data.Appointment I have the predefinied StingList Categories.
What happens now is that I'm parsing through an XML File which looks like:
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="1">
<z:row ows_ContentTypeId="0x010200C5A7325634A3154BB8249D1C36246E00"
ows_Title="Test GetAllViewFields"
ows_Location="Testhausen"
ows_EventDate="2014-12-15 08:00:00"
ows_EndDate="2014-12-15 09:00:00"
ows_Description="Ein Test meeting"
ows_fAllDayEvent="0"
ows_fRecurrence="0"
ows_EventType="0"
ows_RecurrenceID="2014-12-15 08:00:00"
ows_Duration="3600"
ows_ParticipantsPicker=""
***ows_Category="Geschäftlich"***
And than I'm parsing this whole XML Code as a String and check if the name is there:
private void initFromXmlAttribute(System.Xml.Linq.XAttribute x)
{
string AttributeName = x.Name.LocalName.Replace("ows_", "");
try
{
if
(AttributeName == "Category")
{
m_Category= x.Value; //Error implicite convert not possible StringList to String
return;
}
The Error is because m_Category = StringList and x.Value = String.
Does anyone has an idea how to solve this little issue?
I am not familiar with class StringList, but I guess it a Collection.
You can simply initialize a new StringList with the string inside it :
m_Category = new StringList() { x.Value };
Assuming you are asking about this class, you'll see that its constructor accepts an IEnumerable<string>, so you can write:
m_Category=new StringList(new[]{x.Value});
StringList implements IEnumerable so you can also use the collection initializer syntax:
m_Category=new StringList{x.Value};
This creates the class in two steps - first creates an empty object and then calls Add for each item in the initializer
You should be able to create a new Stringlist with the desired values (StringList inherits from List(Of String), so it's quite straightforward:
myStringList = new StringList()
myStringList.add(x.Value)
Btw since you are effectively setting your "Category" Property you might want to consider including a "set" statement to your property instead of modifying your private variable directly. In fact you can skip defining your private variable completely by using:
public StringList Category { get; set; }
Category = new StringList()
The compiler will do the rest for you.
Related
I have a two class properdata and pprosecnddata both classes having property
I want to access product property from properdata class list object. How is it possible,below is my sample code
pupilc class ProperData
{
public string code{get;set;}
public List<ProSecndData>Secnd{get;set;}
}
public class ProSecndData
{
public string product{get;set;}
}
I am trying to call property like that
class Program
{
static void Main(string[] args)
{
ProperData.Secnd.Product = "Hello";
}
}
you cannot directly access property of Secnd as it is a list
you need to iterate or select the index of the List<Secnd>
you must initialize Secnd first and Secnd should have items in the list
properData.Secnd = new List<ProSecndData>();
so it can be access via
foreach(var second in properData.Secnd)
{
second.product = "hello";
}
//or
for(var i = 0; i < proderData.Secnd.Count(); i++)
{
properData.Secnd[i].product = "hello";
}
//or
var index = //0-length of list;
properData.Secnd[index].product = "hello";
if you want to have items first then add first on your Secnd List
properData.Secnd = new List<ProSecndData>();
properData.Secnd.Add(new ProSecndData{ product = "hello"});
then you now can iterate the list by using methods above
You are trying to access list as a single object, which is not possible.
you need to create single instance of your list class and then you can add string in that single instance.
properData.Secnd = new List<ProSecndData>();
ProSecndData proSecndData = new ProSecndData();
proSecndData.product = "Hello";
properData.Secnd.Add(proSecndData);
Actually I know the answer already, you have not created a constructor to initialise your List.
I'm guessing you get a object null ref error?
Create the constructor to initialise your list and it should be fine.
But in future, please post the error message (not the whole stack, just the actual error) as well as all the code required to repeat the issue. Otherwise you run the risk of getting your question deleted
(It should be deleted anyway because it could be considered a "what is a null ref err?" question).
Also you are accessing an item in a list like the list is that item (should be more like: ProperData.Secnd.elementAt(0).product, please also note the capitalisation of 'product' in the model vs your code.
When running the following code I receive an exception "CypherTypeException: Collections containing mixed types can not be stored in properties." - What am I doing wrong, and what needs to change to make it work?
var wordObjs = new List<object>();
foreach (string word in WordGroups.GetAllWords())
{
wordObjs.Add(new { Value = word});
}
GraphClient.Cypher
.Create("(word:Word {words})")
.WithParam("words", new { words = wordObjs})
.ExecuteWithoutResults();
One solution would be use a concrete class
private class Value {
public string Value {get;set;}
}
and use new List<Value>() instead, I think the client is having trouble with the anonymous nature of your List.
I'm attempting to use Enumerable.OrderBy to sort a List because ultimately I want to be able to sort by more than a single field. At the moment it only appears to work if I create a new variable var to hold the results view which means (I think) the types need to be re-cast.
Is there a method to sort a List by more than 1 field whilst retaining the original List variable and types? I.e. I'd rather end up with variable _orderedbins of type List<orderedbins>
Below is what I currently have but everything from var test = ... onwards seems a bit wrong.
public class orderedBins
{
public string Bin { get; set; }
public int Order { get; set; }
}
List<orderedbins> _orderedbins = new List<orderedbins>();
foreach (string item in splitbins)
{
string[] spbinSetting = item.Split(',');
bool bchecked = bool.Parse(spbinSetting[1]);
int border = int.Parse(spbinSetting[2]);
if (bchecked == true)
{
_orderedbins.Add(new orderedbins { bin = spbinSetting[0], Order = border });
}
}
var test =_orderedbins.OrderBy(x => x.Order);
foreach (var item in test)
{
string f = item.Bin;
int g = item.Order;
}
You know, you can perform multiple sub-sorts for an order by...
lst.OrderBy(x => x.Prop1).ThenBy(x => x.Prop2).ThenByDescending(x => x.Prop3)...
Just add a .ToList(); and introduce it with a variable, to have the result in a list variable.
EDIT:
Great suggestion by Willem, for more readability:
from x in lst
order by x.Prop1, x.Prop2, x.Prop3
select x
You can create a new sorted list without creating a new variable using
list = list.OrderBy(item => item.Field1).ThenBy(item => item.Field1).ToList();
It will still create an entirely new list though (it's not actually much of a problem to add a new variable; those are cheap. Creating a new list, doing this, is fine as long as the list isn't very large.
If you need to sort the list in place then you'll want to use a custom comparer with the List's sort method:
public class MyComparer : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
if(x.Field1 != y.Field1)
return x.Field1.CompareTo(y.Field1)
else
return x.Field2.CompareTo(y.Field2);
}
}
List<MyClass> list = new List<MyClass>();
//Populate list
list.Sort(new MyComparer());
As others suggested, using Linq's OrderBy(...).ToList() would be a cleaner way, but this will give you a new instance of the list.
To retain the original instance, consider to use List<T>.Sort():
_orderedbins.Sort(new Comparison<orderedBins>((obj1, obj2) =>
{
int result = obj1.Order.CompareTo(obj2.Order);
return result != 0 ? result : obj1.Bin.CompareTo(obj2.Bin);
}));
This will do the trick:
_orderedbins = _orderedbins.OrderBy(x => x.Order).ToList();
...but there's no real issue creating a new variable/reference.
I think this will do it (it's already a list of orderbins so no casting is required):
_orderbins = _orderbins.OrderBy(x => x.Order).ToList();
In most of the methods I use that return some kind of collection I return IEnumerable rather than the specific type (e.g. List). In many cases I have another collection that I want to combine with the result IEnumerable, this would be exactly like taking a List and adding another List to it using the AddRange method. I have the following example, in it I have created an extension method that should take a collection of items to add and adds them to a base collection, while debugging this appears to works but in the original collection the items are never added. I don't understand this, why aren't they added, is there something about the implementation of the IEnumerable that I am missing? I understand that IEnumerable is a read only interface, but Iam not adding to this list in the example below, I am replacing it, but the original IEnumerable does not change.
class Program
{
static void Main(string[] args)
{
var collectionOne = new CollectionContainerOne();
var collectionTwo = new CollectionContainerTwo();
// Starts at 1- 50 //
collectionOne.Orders.AddRange(collectionTwo.Orders);
// Should now be 100 items but remains original 50 //
}
}
public class CollectionContainerOne
{
public IEnumerable<Order> Orders { get; set; }
public CollectionContainerOne()
{
var testIds = Enumerable.Range(1, 50);
var orders = new List<Order>();
foreach (int i in testIds)
{
orders.Add(new Order() { Id = i, Name = "Order #" + i.ToString() });
}
this.Orders = orders;
}
}
public class CollectionContainerTwo
{
public IEnumerable<Order> Orders { get; set; }
public CollectionContainerTwo()
{
var testIds = Enumerable.Range(51, 50);
var orders = new List<Order>();
foreach (int i in testIds)
{
orders.Add(new Order() { Id = i, Name = "Order #" + i.ToString() });
}
this.Orders = orders;
}
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return this.Name;
}
}
public static class IEnumerable
{
public static void AddRange<T>(this IEnumerable<T> enumerationToAddTo, IEnumerable<T> itemsToAdd)
{
var addingToList = enumerationToAddTo.ToList();
addingToList.AddRange(itemsToAdd);
// Neither of the following works //
enumerationToAddTo.Concat(addingToList);
// OR
enumerationToAddTo = addingToList;
// OR
enumerationToAddTo = new List<T>(addingToList);
}
}
You are modifying the parameter enumerationToAddTo, which is a reference. However, the reference is not itself passed by reference, so when you modify the reference, the change is not observable in the caller. Furthermore, it is not possible to use ref parameters in extension methods.
You are better off using Enumerable.Concat<T>. Alternatively, you can use ICollection, which has an Add(T) method. Unfortunately, List<T>.AddRange isn't defined in any interface.
Here is an example to illustrate the passing of reference types by reference. As Nikola points out, this is not really useful code. Don't try this at home!
void Caller()
{
// think of ss as a piece of paper that tells you where to find the list.
List<string> ss = new List<string> { "a", "b" };
//passing by value: we take another piece of paper and copy the information on ss to that piece of paper; we pass that to the method
DoNotReassign(ss);
//as this point, ss refers to the same list, that now contains { "a", "b", "c" }
//passing by reference: we pass the actual original piece of paper to the method.
Reassign(ref ss);
// now, ss refers to a different list, whose contents are { "x", "y", "z" }
}
void DoNotReassign(List<string> strings)
{
strings.Add("c");
strings = new List<string> { "x", "y", "z" }; // the caller will not see the change of reference
//in the piece of paper analogy, we have erased the piece of paper and written the location
//of the new list on it. Because this piece of paper is a copy of SS, the caller doesn't see the change.
}
void Reassign(ref List<string> strings)
{
strings.Add("d");
//at this point, strings contains { "a", "b", "c", "d" }, but we're about to throw that away:
strings = new List<string> { "x", "y", "z" };
//because strings is a reference to the caller's variable ss, the caller sees the reassignment to a new collection
//in the piece of paper analogy, when we erase the paper and put the new object's
//location on it, the caller sees that, because we are operating on the same
//piece of paper ("ss") as the caller
}
EDIT
Consider this program fragment:
string originalValue = "Hello, World!";
string workingCopy = originalValue;
workingCopy = workingCopy.Substring(0, workingCopy.Length - 1);
workingCopy = workingCopy + "?";
Console.WriteLine(originalValue.Equals("Hello, World!"); // writes "True"
Console.WriteLine(originalValue.Equals(workingCopy); // writes "False"
If your assumption about reference types were true, the output would be "False" then "True"
Calling your extensions method like this:
collectionOne.Orders.AddRange(collectionTwo.Orders);
Is essentially the same as:
IEnumerable.AddRange(collectionOne.Orders, collectionTwo.Orders);
Now what happens there, is you pass copy of reference to the collectionOne.Orders to the AddRange method. In your AddRange implementation you try to assign new value to the copy. It gets "lost" inside. You are not assigning new value to collectionOne.Orders, you assign it to its local copy - which scope is only within the method body itself. As a result of all modifications happenining inside AddRange, outside world notices no changes.
You either need to return new enumerable, or work on lists directly. Having mutating methods on IEnumerable<T> is rather counterintuitive, I'd stay away from doing that.
What you want exists and is called Concat. Essentially, when you do this in your Main:
var combined = collectionOne.Orders.Concat(collectionTwo.Orders);
Here, combined will refer to an IEnumerable that will traverse both source collections when enumerated.
IEnumerable does not support adding. What you in essence did in your code is create new collection from your enumerable, and add items to that new collection. Your old collection still has same items.
E.g., you create a collection of numbers like this
Collection1 = [ 1, 2, 3, 4, 5 ]
when you do Collection1.ToList().Add(...) you will get new collection with same members, and add new members like so:
Collection1 = [ 1, 2, 3, 4, 5, 6, 7, ... ]
your old collection will however still hold old members, as ToList creates new collection.
Solution #1:
Instead of using IEnumerable use IList which supports modification.
Solution #2 (bad):
Cast your IEnumerable back to it's derived type and add members to it. This is quite bad though, in fact it's better to just return List in the first place
IEnumerable<Order> collectionOne = ...;
List<Order> collectionOneList = (List<Order>)collectionOne;
collectionOneList.Add(new Order());
General guideline (best):
If you are returning collections which are standard in .NET there is no reason to return their interfaces. In this case it's best to use original type. If you are however returning collection which you implemented yourself, then you should return an interface
It's a completely different case when you are thinking about input parameters. If your method is asking to enumerate over items, then you should ask for IEnumerable. This way you can do what you need over it, and you are placing least constraint on person who is calling it. They can send any enumerable. If you need to add to that collection, you may require IList so that you can also modify it in your method.
Basically the problem is that you can't assign a value to enumerationToAddTo partially because it isn't a reference parameter. Also as phoog mentions ToList() creates a new list and does not cast the existing IEnumerable to a list.
This isn't really a good use of a extension. I would recommend that you add a method to your container collection that allows you add add new items to the IEnumerable instance. This would better encapsulate the logic that's particular to that class.
I have a list
List<MyObject> myList
and I am adding items to a list and I want to check if that object is already in the list.
so before I do this:
myList.Add(nextObject);
I want to see if nextObject is already in the list.
The object "MyObject" has a number of properties but comparison is based on matching on two properties.
What is the best way to do a check before I add a new "MyObject" to this list of "MyObject"s.
The only solution I thought up was to change from a list to a dictionary and then make the key a concatenated string of the properties (this seems a little unelegant).
Any other cleaner solutions using list or LINQ or something else?
It depends on the needs of the specific situation. For example, the dictionary approach would be quite good assuming:
The list is relatively stable (not a lot of inserts/deletions, which dictionaries are not optimized for)
The list is quite large (otherwise the overhead of the dictionary is pointless).
If the above are not true for your situation, just use the method Any():
Item wonderIfItsPresent = ...
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);
This will enumerate through the list until it finds a match, or until it reaches the end.
Simply use Contains method:
bool alreadyExist = list.Contains(item);
Note that it works based on the equality function Equals. Check the example of the link above if you need to implement Equals function.
If it's maintainable to use those 2 properties, you could:
bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");
Are you sure you need a list in this case? If you are populating the list with many items, performance will suffer with myList.Contains or myList.Any; the run-time will be quadratic. You might want to consider using a better data structure. For example,
public class MyClass
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class MyClassComparer : EqualityComparer<MyClass>
{
public override bool Equals(MyClass x, MyClass y)
{
if(x == null || y == null)
return x == y;
return x.Property1 == y.Property1 && x.Property2 == y.Property2;
}
public override int GetHashCode(MyClass obj)
{
return obj == null ? 0 : (obj.Property1.GetHashCode() ^ obj.Property2.GetHashCode());
}
}
You could use a HashSet in the following manner:
var set = new HashSet<MyClass>(new MyClassComparer());
foreach(var myClass in ...)
set.Add(myClass);
Of course, if this definition of equality for MyClass is 'universal', you needn't write an IEqualityComparer implementation; you could just override GetHashCode and Equals in the class itself.
Another point to mention is that you should ensure that your equality function is as you expect. You should override the equals method to set up what properties of your object have to match for two instances to be considered equal.
Then you can just do
mylist.contains(item)
Here is a quick console app to depict the concept of how to solve your issue.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
public class myobj
{
private string a = string.Empty;
private string b = string.Empty;
public myobj(string a, string b)
{
this.a = a;
this.b = b;
}
public string A
{
get
{
return a;
}
}
public string B
{
get
{
return b;
}
}
}
class Program
{
static void Main(string[] args)
{
List<myobj> list = new List<myobj>();
myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") };
for (int i = 0; i < objects.Length; i++)
{
if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; })))
{
list.Add(objects[i]);
}
}
}
}
}
Enjoy!
Edit: I had first said:
What's inelegant about the dictionary solution? It seems perfectly elegant to me, especially since you only need to set the comparator in creation of the dictionary.
Of course though, it is inelegant to use something as a key when it's also the value.
Therefore I would use a HashSet. If later operations required indexing, I'd create a list from it when the Adding was done, otherwise, just use the hashset.
Simple but it works
MyList.Remove(nextObject)
MyList.Add(nextObject)
or
if (!MyList.Contains(nextObject))
MyList.Add(nextObject);
A collection can be used as a dictionary, where the difference is that you don't need to a reference to Microsoft Scripting Runtime or use late binding. Please note that in this case the key must be a string. In my case the key(number) is integer, but declared as string.
You can create a custom Boolean function to check if the key exists in the list.
There is a good article be Paul Kelly on ExcelMacroMastery.com
' Function to check if item in the collection already exists
Function Exists(coll As Collection, key As String) As Boolean
On Error GoTo EH
IsObject (coll.Item(key))
Exists = True
EH:
End Function
end you can use it like this
For i = 3 To lastRow
' Ignore the Normal areas
If rg.Cells(i, 1).value <> "Normal" Then
number = rg.Cells(i, 1).value
' Check if the area exist in the collection using a custom function Exists
If Exists(coll, number) = False Then
Set oRiskArea = New clsHighRiskArea
oRiskArea.number = number
coll.add key:=oRiskArea.number, Item:=oRiskArea
Else
Set oRiskArea = coll(number)
End If
With oRiskArea
.name = rg.Cells(i, 2).value
End With
End If
Next i