I'm trying to initalize an object for serialization, the class object was created using xsd.exe. The individual properties can be initialised without issue but when trying to initialise an 'unbounded' XSD property i can't use a foreach loop to go over each value in an array and add that to the object:
object[] test = new object[0];
test[0] = "ring";
export export = new export();
export.info = new exportInfo
{
dateandtimeofexport = DateTime.Now,
duration = "10",
planningsoftware = new exportInfoPlanningsoftware
{
name = "",
major = "",
minor = "",
revision = "",
build = ""
},
exporter = new exportInfoExporter
{
version = new exportInfoExporterVersion
{
name = "",
major = "",
minor = "",
revision = "",
build = ""
},
module = new exportInfoExporterModule[]
{
foreach(Object x in test)
{
new exportInfoExporterModule{name = x.name, major = x.major, minor = x.minor, revision = x.revision, build = x.build;}
}
}
}
};
I think the main problem here is my understanding of exactly how to initialise an array of objects under the object class created from my XSD using XSD.exe, can anyone advise on how this might be done without the foreach loop?
Any guidance is much appreciated.
Your code is not valid c#. You cannot use foreach inside an array initializer.
// NOT VALID C# CODE!
module = new exportInfoExporterModule[]
{
foreach(Object x in test)
{
new exportInfoExporterModule{name = x}
}
}
This is not possible, because foreach is a statement, but the array intializer expects an expression that results in a exportInfoExportedModule.
What you can do instead is something like this:
module = test.Select(x => new exportInfoExporterModule{name = x}).ToArray()
But note that at the start of your code you create the array test with length 0 and then try to set "ring" as its first (of zero) elements! That gives an IndexOutOfRangeException. Initialize test like that:
object[] test = new object[] {"ring"};
module = test.Select(t => new exportInfoExporterModule{name = t}).ToArray()
instead of
module = new exportInfoExporterModule[]
{
foreach(Object x in test)
{
new exportInfoExporterModule{name = x}
}
}
should do the trick. Learn some LINQ at it will get clear what happened here ;)
You can't use a loop within an initializer.
See if you can initialize the array after you've constructed the rest of the object:
export.info = new exportInfo
{
// ...
version = new exportInfoExporterVersion
{
name = "",
major = "",
minor = "",
revision = "",
build = ""
}
}
};
export.info.exporter.module = new exportInfoExporterModule[test.Length];
for (int i = 0; i < test.Length; i++)
{
export.info.exporter.module[i] = new exportInfoExporterModule
{
name = test[i].name,
major = test[i].major,
minor = test[i].minor,
build = test[i].build,
revision = test[i].revision
};
}
Or, with LINQ:
export.info = new exportInfo
{
// ...
version = new exportInfoExporterVersion
{
name = "",
major = "",
minor = "",
revision = "",
build = ""
},
module = test.Select(x => new exportInfoExporterModule
{
name = x.name,
major = x.major,
minor = x.minor,
build = x.build,
revision = x.revision
}).ToArray()
}
};
The first two lines of your code will result in a runtime exception, as you're attempting to put a value in a zero-length array.
object[] test = new object[0];
test[0] = "ring";
Run-time exception (line -1): Index was outside the bounds of the array.
Here is a .NET Fiddle to show that.
Iterating over an array via a foreach is totally fine! But the issue is really that the loop is within an object initializer. This is not permitted, instead use Linq with a .Select and .ToArray().
module = test.Select(t => new exportInfoExporterModule { name = t })
.ToArray();
You have to create the array you want to assign before you create your exporter object.
Another way could be to use Linq to assign module. Something like
module = test.Select(x => new exportInfoExporterModule{name = x}).ToArray()
should work.
To be able to use a foreach you have to iterate on a container implementing interface IEnumerable.
It is not the case of a simple array. Just transform test in a List (List implements IEnumerable) and it should work.
List<object> test = new List<object>();
Related
I am trying to use the "Put_Ledger" function inside the Financial_management API in Workday, but I keep on getting an error when I try to add the object[] to the object (as it states in the API to do).
Workday has been no help in solving this issue. Here is a sample of the code. The objects are creates, and then added to parent objects:
Ledger_Only_DataType ldOnly = new Ledger_Only_DataType
{
Actuals_Ledger_ID = "1234567",
Can_View_Budget_Date = true
};
//Commitment_Ledger_data
Commitment_Ledger_Data__Public_Type cl = new Commitment_Ledger_Data__Public_Type
{
Commitment_Ledger_Reference = ledgerObject,
Enable_Commitment_Ledger = true,
Spend_Transaction_Data = st,
Payroll_Transaction_Data = pt
};
// This is where the error occurs:
ldOnly.Commitment_Ledger_Data = cl;
Error message:
"Cannot implicitly convert type 'CallWorkdayAPI.Financial_Management.Commitment_Ledger_Data__Public_Type' to 'CallWorkdayAPI.Financial_Management.Commitment_Ledger_Data__Public_Type[]"
Use lists and convert them to an array. It's easier:
List<Commitment_Ledger_Data__Public_Type> cls = new List<Commitment_Ledger_Data__Public_Type>();
Commitment_Ledger_Data__Public_Type cl1 = new
Commitment_Ledger_Data__Public_Type
{
Commitment_Ledger_Reference = ledgerObject,
Enable_Commitment_Ledger = true,
Spend_Transaction_Data = st,
Payroll_Transaction_Data = pt
};
cls.Add(cl1);
ldOnly.Commitment_Ledger_Data = cls.ToArray();
You can simplify and do it inside the initializer as well
Not familiar with Workday, but I am assuming
ldOnly.Commitment_Ledger_Data
Is an array of: Commitment_Ledger_Data__Public_Type
So you need to set it equal to an array of that type, whereas currently you are setting it equal to a single object of that type.
Ledger_Only_DataType ldOnly = new Ledger_Only_DataType
{
Actuals_Ledger_ID = "1234567",
Can_View_Budget_Date = true
};
//Commitment_Ledger_data
Commitment_Ledger_Data__Public_Type cl = new
Commitment_Ledger_Data__Public_Type
{
Commitment_Ledger_Reference = ledgerObject,
Enable_Commitment_Ledger = true,
Spend_Transaction_Data = st,
Payroll_Transaction_Data = pt
};
Commitment_Ledger_Data__Public_Type[] cls = new Commitment_Ledger_Data__Public_Type[1];
cls[0] = cl;
ldOnly.Commitment_Ledger_Data = cls;
The error message is telling you what the problem is - you're trying to assign a single instance of a Commitment_Ledger_Data__Public_Type type to an object that represents an array of that type (Commitment_Ledger_Data).
You should be able to do the assignment using an array (with the single item you created as it's only member) instead:
ldlOnly.Commitment_Ledger_Data = new[] {cl};
Or you could shorten the whole thing to use initializer syntax:
var ldOnly = new Ledger_Only_DataType
{
Actuals_Ledger_ID = "1234567",
Can_View_Budget_Date = true,
Commitment_Ledger_Data = new[]
{
new Commitment_Ledger_Data__Public_Type
{
Commitment_Ledger_Reference = ledgerObject,
Enable_Commitment_Ledger = true,
Spend_Transaction_Data = st,
Payroll_Transaction_Data = pt
}
}
};
Is it possible something like this? I've worked hard, but I think it's not possible, I hope someone will help me.
I have to fill the object like this,
var obj = new
{
parentObj = new List<object>()
{
outsideArray.ForEach(x=>
{
})
}
}
I dont like this.
var obj = new
{
parentObj= new List<object>()
{
new object() { bla, bla }
}
}
I want to do.
var obj {
Id =1,
Name= "any",
Address = new {
userAddressList.forEach(x=> {
Town = x.town,
State = x.state
}
}
}
The code in the second and third code snippets does not comply to C# syntax.
However, you may use LINQ to fill your array nicely similar to what shown in the third snippet:
var obj = new
{
Id = 1,
Name = "any",
Address = userAddressList.Select(x =>
{
Town = x.town,
State = x.state
})
};
i have searched for something similiar in stackoverflow and couldnt find anything which will give me some hint.
i have following code:
DATA val1 = new DATA();
val1.Name = "KeyValue";
val1.Value = "805373069";
DATA val2 = new DATA();
val2.Name = "Tel";
val2.Value = "0123456789";
DATA val3 = new DATA();
val3.Name = "TargetID";
val3.Value = "43301";
DATA val4 = new DATA();
val4.Name = "ServiceLevel";
val4.Value = "Y";
DATA val5 = new DATA();
val5.Name = "TypeId";
val5.Value = "13505";
DATA val6 = new DATA();
val6.Name = "DateTime";
val6.Value = System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt");
DATA val7 = new DATA();
val7.Name = "DbDateTime";
val7.Value = System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt");
and once all the objects are populated i put them in Single array.
i.e. to be used somewhere else
DATA[] array = {val1,val2,val3,val4,val5,val6,val7};
and Proxy class which i cant change is:
public partial class DATA {
private string nameField;
private string valueField;
public string Name {
get {
return this.nameField;
}
set {
this.nameField = value;
this.RaisePropertyChanged("Name");
}
}
public string Value {
get {
return this.valueField;
}
set {
this.valueField = value;
this.RaisePropertyChanged("Value");
}
}
Now what i have tried and failed to make it easier is used Dictionary and also jagged array and multi dimensional array which didnt worked as i hoped.
can someone give me hint of a better solution then having 7 different objects created, as this data is dynamic i have to do this runtime data population.
suggestions please?
You could just declare the objects in-line as part of the array declaration, if all you're trying to do is avoid having the variables:
DATA[] array = {
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" }
};
Anywhere that you have a variable, you can instead have the operation which created that variable. The order of operations will result in evaluating to the same thing. Where you'd need a variable is where you want to use the same instance of something multiple times, or the same value without having to re-calculate it.
Put all data in a dictionary if you want to make sure names must not be duplicated:
var data = new Dictionary<string, string>();
// fill dictionary:
data.Add("name1", /*value*/);
data.Add("name2", /*value*/);
data.Add("name3", /*value*/);
data.Add("name4", /*value*/);
Then convert it to array:
return data.Select(d => new Data(){ Name = d.Key, Value = d.Value}).ToArray();
Make sure you have included using System.Linq in top.
UPDATE:
As #LukeH suggested, You can simply use collection initializer like this:
var data = new Data[]
{
new Data(){ Name = "Sylvester", Value = /*value*/ },
new Data(){ Name = "Whiskers", Value = /*value*/ },
new Data(){ Name = "Sasha", Value = /*value*/ }
};
Which doesn't prevent duplicate names for Data type instances.
You can create extension method something like this to overcome the problem of assign properties values rather then duplication,
static class Extensions
{
public static void AddDataObject(this List<DATA> dataList, params string[] values)
{
dataList.Add(new DATA() { Name = values[0], Value = values[1] });
}
}
and passing that values as per given below,
List<DATA> dataList = new List<DATA>();
dataList.AddDataObject("KeyValue", "805373069");
dataList.AddDataObject("Tel", "0123456789");
Here in above example I used List instead of array, you can change according to your requirements
You could initialize an anonymous object and then convert to an array of data like this:
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array = data.GetType()
.GetProperties()
.Select(x=>new DATA{Name=x.Name,Value=(string)x.GetValue(data)})
.ToArray();
You could also do it like this:
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array=System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes(data)
.Select(x=>new DATA {Name=x.Key,Value=(string)x.Value})
.ToArray();
If you need to take an array of data and convert it back into a class object (not anonymous), you can do the first method, just in reverse as well. Or put extension methods on it to convert from/to your data array.
static class Extensions
{
public static DATA[] ToDataArray(this object data)
{
return data.GetType()
.GetProperties()
.Select(x=>new DATA{Name=x.Name,Value=(string)x.GetValue(data)})
.ToArray();
}
}
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array=data.ToDataArray();
However, David's answer is better.
I'm playing around with the new driver of mongodb 2.0, and looking for adding some facetted searchs (Temporary move ,before using elastic search).
Here is some method where I created to build the agreggation. I guess that it should work.
As parameter I passed also a filterdefinition in the method.
But I don't find how to limit my agreggation to the filter.
Any Idea ???
private void UpdateFacets(SearchResponse response, FilterDefinition<MediaItem> filter, ObjectId dataTableId)
{
response.FacetGroups =new List<SearchFacetGroup>();
SearchFacetGroup group = new SearchFacetGroup()
{
Code = "CAMERAMODEL",
Display = "Camera model",
IsOptional = false
};
using (IDataAccessor da = NodeManager.Instance.GetDataAccessor(dataTableId))
{
var collection = da.GetCollection<MediaItem>();
var list = collection.Aggregate()
.Group(x => ((ImageMetaData) x.MetaData).Exif.CameraModel, g => new { Model = g.Key, Count = g.Count() })
.ToListAsync().Result;
foreach (var l in list)
{
group.Facets.Add(new SearchFacetContainer()
{
Code = l.Model,
Display = l.Model,
Hits = l.Count,
IsSelected = false
});
}
}
response.FacetGroups.Add(group);
}
I haven't used facet, but with Mongo driver Aggregate has .Match operation that accepts a filterdefinition.
collection1.Aggregate().Match(filter)
I have a fairly unique situation, I have never needed to this before anyways. I have a Linq query that returns data from a database using EF4.1. I want to create multiple similar (same signature) anonymous (or even named if necessary) results from each query result.
Here's the code i'm using now:
var data = getMyData().Select(x =>
new
{
GoalName = x.GoalType.Name,
Start = x.StartDate,
End = x.EndDate,
x.StartValue,
x.CheckIns
}).ToList();
var r1 = data.Select(x =>
new
{
title = x.GoalName,
start = x.Start.ToString(),
end = x.End.ToString(),
className = "hidden",
type = "goal"
});
var r2 = data.Select(x =>
new
{
title = string.Format("Start: {0:0.##}", x.StartValue),
start = x.Start.ToString(),
end = x.Start.ToString(),
className = "",
type = ""
});
var r3 = data.Select(x =>
new
{
title = "End",
start = x.End.ToString(),
end = x.End.ToString(),
className = "",
type = ""
});
var r4 = data.SelectMany(x => x.CheckIns)
.Select(y =>
new
{
title = y.CheckInValue.Value.ToString(),
start = y.CheckInDateTime.ToString(),
end = y.CheckInDateTime.ToString(),
className = "",
type = ""
});
var result = r1.Union(r2).Union(r3).Union(r4);
Now maybe this is as good a way as any, but I can't help feeling that i'm missing something.
Is there a better solution?
What you have is actually OK I think.
But StevenzNPaul's suggestion not that bad, here's how you can use the let keyword to store the different projections, then select the results individually (for brevity, I did not project all the fields, but you get the point):
var query = from x in data
let result1 = new {title = x.GoalName, start = x.Start}
let result2 = new {title = string.Format("Start: {0:0.##}", x.StartValue), start = x.Start}
let result3 = new {title = "End", start = x.End}
let checkins = x.CheckIns.Select(checkin => new { title = "...", start = checkin.Start })
from result in new[] { result1, result2, result3 }.Concat(checkins)
select result;
Obviously, whether this is better is a matter of preference. Also, this will result in a different ordering, which may or may not be a problem for you.
You can create an iterator using yield which also has the advantage of being evaluated lazily (doesn't require the ToList()). I created a typed class Result to hold the query results
private IEnumerable<Result> PerformQuery()
{
var results= getMyData().Select(x => new {GoalName = x.GoalType.Name,
Start = x.StartDate, End = x.EndDate, x.StartValue, x.CheckIns});
foreach (var result in results)
{
yield return new Result() { Title = result.GoalName, Start = result.Start.ToString(), End = result.End.ToString(), ClassName = "Hidden", Type = "Goal" };
yield return new Result() { Title = String.Format("Start: {0:0.##}",result.StartValue), Start = result.Start.ToString(), End = result.Start.ToString() }
yield return new Result() { Title = "End", Start = result.End.ToString(), End = result.End.ToString() };
foreach (var checkIn in result.CheckIns)
yield return new Result() { Title = checkIn.CheckInValue.Value.ToString(), Start = checkIn.CheckInDateTime.ToString(), End = checkIn.CheckInDateTime.ToString() };
}
}
try using let keyword it will work for you.