List<> Filling Error (Void) - c#

For my work I need to create a page that gets all the data for that page from a database using the kellerman framework.
The problem is that I can't seem to create a certain part.
List<TextBlockDataObject> t = new List<TextBlockDataObject>();
t.Add(new TextBlockDataObject() { Translations = (List<content new List<ContentTranslationDataObject>().Add(new ContentTranslationDataObject() { LangueageCode = "Eng", TextValue = "TestingText" } ) });
Error: Cannot implicitly convert type 'void' to
When I try to build the object trough a other way I get other errors related to bad object creation.
Other Code I used for testing
var tmpTextDataObjs = new List<TextBlockDataObject>();
tmpTextDataObjs.Add(new TextBlockDataObject());
List<ContentTranslationDataObject> ContentTransDataObject = new List<ContentTranslationDataObject>();
ContentTransDataObject.Add(new ContentTranslationDataObject() { LangueageCode = "Eng", TextValue = "this is a test.." });
tmpTextDataObjs[0].Translations = ContentTransDataObject.ToArray();
tmpPage.TextBlockDataObjects = tmpTextDataObjs.ToArray();
var titleObj = new List<ContentTranslationDataObject>();
titleObj.Add(new ContentTranslationDataObject(){LangueageCode = "Eng", TextValue = "444"});
tmpPage.TitleTranslations = titleObj.ToArray();
the code above works for a few elements but in the end the page doesn't get created.
Hope anyone can help me out!

The problem is that you are calling Add() on a newly created List object that you are trying to add to another List property. Add() returns void, not the new list.
Split up your declarations and assignments and you should be fine. Also, I recommend using the var keyword to lessen code duplication/boilerplate as well as using IList instead of List (always use a more generic type/interface when possible).
If you want to initialize the objects inline you can use the anonymous array initializer syntax.
IList<myType> myList = new[] { new myType(), new myType() };

Related

Index dynamic Objects with ElasticSearch Nest - StackOverflow Exception

I want to index a collection of dynamic objects using the ElasticSearch Nest Client.
The objects are first materialized by NewtonsoftJson.NET from a JSON file into dynamic objects and then manipulated by the program. All objects get a property "Id". This should serve as "_id" field for ElasticSearch.
The "_id" field must be the same for identical data records in order to be able to update data later.
Because attributes "IdProperty" cannot be added to a dynamic object and a
mapping can also not be used, I was forced to the following solution.
I would like to keep the dynamic objects because I manipulate only a few properties and the other properties are of no interest to me.
var values = new List<dynamic>();
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Id = "ABC";
obj.SomeValue0 = "12";
obj.SomeValue1 = 99;
values.Add(obj);
var descriptor = new BulkDescriptor();
// Now i want to Index this List
foreach (var doc in values) {
// Here the StackOverflowException will be thrown
descriptor.Index<object>(i => i
.Index("abc")
.Id(doc.Id)
.Document(doc));
}
client.Bulk(descriptor);
(Index a dynamic object using NEST - This was my inspiration)
This example raises a StackOverflow exception during indexing. It does not matter whether one or more objects are in the list.
Interestingly, the following method works without problems. The only thing that doesn't work is the
ElasticSearch "_id" field was generated automatically and therefore does not correspond to the "Id" field.
client.IndexMany(value, index);
What am I doing wrong with the first possibility and is there a possibility to set a "_id" on a dynamic object?
You need to
cast the Id property to string (or Nest.Id if it could be another type with an implicit conversion to Nest.Id, for example, Guid
cast the object to object
Here's an example
var client = new ElasticClient();
var values = new List<dynamic>();
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Id = "ABC";
obj.SomeValue0 = "12";
obj.SomeValue1 = 99;
values.Add(obj);
var descriptor = new BulkDescriptor();
// Now i want to Index this List
foreach (var doc in values)
{
descriptor.Index<object>(i => i
.Index("abc")
.Id((Id)doc.Id)
.Document((object)doc));
}
client.Bulk(descriptor);
which will send a request like the following
POST http://localhost:9200/_bulk
{"index":{"_index":"abc","_type":"object","_id":"ABC"}}
{"Id":"ABC","SomeValue0":"12","SomeValue1":99}
Dynamic types don't play nicely with generic types and member access expressions, which looks to be related to runtime type resolution. In the example above, I would recommend using anonymous types and a List<object>

Pass an array or list of different objects to a function for modification

Currently I am receiving an array of objects from a database.
object [] sqlResultData = DatabaseCall.Result();
This array of objects needs to be matched to class variables like this
CClassOfVars classVar = new CClassOfVars();
classVar.myProperty = sqlResultData[0];
classVar.myProperty1 = sqlResultData[1];
What i wish to do is pass the list of propertys on the class in order to a function and have the mapping from the object array occur automatically based on the order.
For example:
Method defined like this
FillData(object [] databaseValues, IList<object>())
Called like this
CClassOfVars classVar = new CClassOfVars();
object [] sqlResultData = DatabaseCall.Result();
FillData(sqlResultData, new List<object>(){classVar.myProperty,classVar.myProperty1});
The FillData function would hopefully type cast and set the values of myProperty and myProperty1 to the values in array locations of 0,1 etc...
Something like this
FillData(object [] databaseValues, IList<object> mapMe)
{
for (int i = 0; i < mapMe.Count; i++)
{
mapMe[i] = CastToTheCorrectType(mapMe[i], databaseValues[i]);
}
}
Cast to the correct type could look like this?? I took from here: cast object with a Type variable
public T CastToTheCorrectType<T>(T hackToInferNeededType, object givenObject) where T : class
{
return givenObject as T;
}
How can i pass a list of different object types to all have there values modified and assigned within a different function?
The matter you asking about is dark and difficult to be implemented through just a function. There are frameworks out there dealing with object relational mapping. If it is an option, install and learn some OR/M. If not ... well, there might be some dirty way.
You can use the JSON.NET library to do the heavy lifting for you. It's super easy to use and install through Nuget. My point is as follows.
Construct an anonymous object. Use the property names of the original object.
Fill it with the data from the object array. Spin a loop over the object array...
Serialize the anonymous object.
Deserialize the JSON string into the target type.
At this point, JSON.NET will handle property mapping for you.
List item
E.g. if your target type is Person you might do this:
var x = new
{
FirstName = String.Empty,
LastName = String.Empty
};
var persons = new List<Person>(sqlResultData.Length);
foreach (var record in sqlResultData)
{
x.FirstName = record[0];
x.LastName = record[1];
var s = JsonConvert.SerializeObject(x)`
var personX = JsonConvert.Deserialize<Person>(s);
persons.Add(person);
}

Count objects within dynamic anonymous object (C#)

I have a dynamic object (it's actually json) that I pass into my MVC WebApi controller.
The json object contains multiple lists within an anonymous object that are submitted to the controller from another application via client.PostAsJsonAsync("myapiurl", objectGraph).
What I need to do to validate the object on the MVC side, is to get the count of objects in each list. I can access the lists dynamically via mydynamicobject.mylist and individual items via mydynamicobject.mylist[index] but I can't seem to be able to get a count of mydynamicobject.mylist.
What I've tried so far:
LINQ extension methods - doesn't work on dynamic
Enumerable.Count(mydynamicobject.mylist) - can't infer type
Any other ideas? The count is actually correctly available in the dynamic object's base but obviously not accessible as a property. Help!
This works now:
// This is a MVC/WebApi method
public dynamic Post(dynamic mydynamicobject)
if (((ICollection)mydynamicobject.mylist).Count == 0)
{
// do something
}
The code that sends the dynamic object (different app):
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add
(new MediaTypeWithQualityHeaderValue("application/json"));
var objectGraph = new { mylist = new { Id = 1 }, mylist2 = new { Name = "ABC" } };
var r = client.PostAsJsonAsync("api/mycontroller", objectGraph).Result;
If they are arrays, I believe you're looking for their Length property.
mydynamicobject.mylist.Length
Alternatively, I think you might be able to get away with casting mydynamicobject.mylist to an IEnumerable and then hand it to IEnueramble.Count like so:
IEnumerable.Count((IEnumerable)mydynamicobject.mylist);
you could also do as Paolo mentioned:
((ICollection)mydynamicobject.mylist).Count
Although I can't take credit for that one.

List<> of objects, different types, sort and pull out types individually?

I've got a handful of products, any, all, or none of which may be associated with a specific submission. All 7 products are subclasses of the class Product. I need to store all the products associated with a submission, and then retrieve them and their field data on my presentation layer. I've been using a List<Product>, and List<object>, but when I use the OfType<EPL(specific subclass)>, I throw an error saying that I can't implicitly convert systems.generic.IEnumerable<EPL> to type 'Product'. I've tried to cast, but to no avail.
When I use prodlist.OfType<EPL>(); there are no errors, but when I try and store that in an instance of EPL "tempEpl", I get the aforementioned cast-related error. What gives? Code below.
ProductService pserv = new ProductService();
IList<object> prodlist = pserv.getProductById(x);
EPL tempEpl = new EPL();
if ((prodlist.OfType<EPL>()) != null)
{
tempEpl = prodlist.OfType<EPL>(); // this throws a conversion error.
}
the Data layer
List<object> TempProdList = new List<object>();
conn.Open();
SqlCommand EplCmd = new SqlCommand(EPLQuery, conn);
SqlDataReader EplRead = null;
EplRead = EplCmd.ExecuteReader();
EPL TempEpl = new EPL();
if (EplRead.Read())
{
TempEpl.Entity1 = EplRead.GetString(0);
TempEpl.Employees1 = EplRead.GetInt32(1);
TempEpl.CA1 = EplRead.GetInt32(2);
TempEpl.MI1 = EplRead.GetInt32(3);
TempEpl.NY1 = EplRead.GetInt32(4);
TempEpl.NJ1 = EplRead.GetInt32(5);
TempEpl.PrimEx1 = EplRead.GetInt32(6);
TempEpl.EplLim1 = EplRead.GetInt32(7);
TempEpl.EplSir1 = EplRead.GetInt32(8);
TempEpl.Premium1 = EplRead.GetInt32(9);
TempEpl.Wage1 = EplRead.GetInt32(10);
TempEpl.Sublim1 = EplRead.GetInt32(11);
TempProdList.Add(TempEpl);
}
This code makes no sense:
Product tempEpl = new EPL();
if ((prodlist.OfType<EPL>()) != null)
{
prodlist.OfType<EPL>();
}
It's unclear why you're creating a new EPL() to start with
OfType() will never return null - it returns a sequence, which may be empty
Calling OfType() won't do anything useful on its own, as per the body of your if statement
It's important to understand that OfType() returns a sequence, not a single item. I suspect that's what you were missing before.
I suspect you want:
Product tempEpl = prodList.OfType<EPL>().FirstOrDefault();
This will assign a value of null to tempEpl if there are no elements of type EPL in prodList, or the first EPL element in the list otherwise.
(It's not clear why you're returning a List<object> from the data layer to start with. Why not a List<Product>?)
I think in DAL instead of returning a list of Object type you should return a list of Product type. If you do so then there is no need for casting it to Product type again.
Second thing, in the PL, instead of using IList just use List.

Copy array of objects to array of different type

Previously, I ran into a problem trying to share a type definition between my ASMX webservice and my .aspx page (webclient)
Confused on C# Array of objects and implicit type conversion
As I understand the advice, the "problem" this creates can be solved by copying the array of objects created in the client to a new array of objects as defined by the ASMX proxy class.
Being a rookie in C# I am still struggling with this simple task. Here are more parts of my code (the other fragments in the previous post remain unchanged):
... here is where I populate the "test data" I want to pass to the web service:
// create an array of MetaData objects
MetaData[] nvPairs = new MetaData[20]; // arbitrary length of 20 pairs
// create arbitrary MetaData objects in the array
nvPairs[0] = new MetaData("Grant Number", "2577-9912");
nvPairs[1] = new MetaData("OPEAnalyst", "Simpson");
... here I attempt a function to "copy" from "real" type defined in my TRIMBrokerUtil namespace (which I can't use completely because of the proxy) to the proxy version of that type:
protected TRIMBrokerASMXProxy.ASMXProxy.MetaData[] CopyMetaData(
MetaData utilArray)
{
TRIMBrokerASMXProxy.ASMXProxy.MetaData[] outArray =
new TRIMBrokerASMXProxy.ASMXProxy.MetaData[utilArray.Name.Length];
int i;
for (i = 0; i < utilArray.Name.Length; i++)
{
outArray[i].Name = utilArray.Name;
outArray[i].Value = utilArray.Value;
}
return outArray;
}
... and then here is where I try to call that function (compiler flags 2 errors on this line:
TRIMBrokerASMXProxy.ASMXProxy.MetaData[] kvData =
CopyMetaData(metaDataArray);
Both of the compile errors below point to the same line:
Error 1 The best overloaded method match for '_Default.CopyMetaData(TRIMBrokerUtil.MetaData)' has some invalid arguments
Error 2 Argument '1': cannot convert from 'TRIMBrokerUtil.MetaData[]' to 'TRIMBrokerUtil.MetaData'
Am I close ?
You've declared your parameter to be MetaData rather than MetaData[] - in other words it's not an array. You're then using utilArray.Name rather a lot, but it's not clear why.
I suspect you actually want:
protected TRIMBrokerASMXProxy.ASMXProxy.MetaData[]
CopyMetaData(MetaData[] utilArray)
{
TRIMBrokerASMXProxy.ASMXProxy.MetaData[] outArray =
new TRIMBrokerASMXProxy.ASMXProxy.MetaData[utilArray.Length];
for (int i = 0; i < utilArray.Length; i++)
{
outArray[i] = new TRIMBrokerASMXProxy.ASMXProxy.MetaData();
outArray[i].Name = utilArray[i].Name;
outArray[i].Value = utilArray[i].Value;
}
return outArray;
}
By the way, you might want to consider a using directive to make this easier to read:
using ProxyMetaData = TRIMBrokerASMXProxy.ASMXProxy.MetaData;
...
protected ProxyMetaData[] CopyMetaData(MetaData[] utilArray)
{
ProxyMetaData[] outArray = new ProxyMetaData[utilArray.Length];
for (int i = 0; i < utilArray.Length; i++)
{
outArray[i] = new ProxyMetaData();
outArray[i].Name = utilArray[i].Name;
outArray[i].Value = utilArray[i].Value;
}
return outArray;
}
Another alternative is Array.ConvertAll:
ProxyMetaData[] output = Array.ConvertAll(input,
metaData => new ProxyMetaData(metaData.Name, metaData.Value));
If you're not using C# 3 you can use an anonymous method for that. If ProxyMetaData doesn't have an appropriate constructor and you are using C# 3, you can use an object initializer:
ProxyMetaData[] output = Array.ConvertAll(input,
metaData => new ProxyMetaData { metaData.Name, metaData.Value });
If you're stuck with C# 2 and no appropriate constructor, then:
ProxyMetaData[] output = Array.ConvertAll(input, delegate(MetaData metaData)
{
ProxyMetaData proxy = new ProxyMetaData();
proxy.Name = metaData.Name;
proxy.Value = metaData.Value;
});
I think that's covered all the bases :)
I would just use LINQ to do this:
TRIMBrokerASMXProxy.ASMXProxy.MetaData[] kvData =
metaDataArray.Select(d =>
new TRIMBrokerASMXProxy.ASMXProxy.MetaData(
d.Name, d.Value)).ToArray();
Additionally, if you are using .NET 3.5, it means you can use WCF as well, which is what you should be using to generate the proxy. You would be able to attribute your TRIMBrokerASMXProxy.ASMXProxy.MetaData type with the DataContract attribute and the members being serialized with the DataMember attribute. Then, you would be able to define your contract with the actual type, and not have to perform conversion at all.
You can also use Array.ConvertAll. I know youre relatively new to this so let me try to explain. It has 2 generic parameters. The first one being the type of the array it wants to convert(lets call it I). And the second one the type you want to convert to (lets call it O). It accepts an array of type I and returns an array of type O. The second parameter is a Converter delegate. Applying the naming we have its signature goes like.
delegate O Converter(I input);
The body of the delegate must contain the code necessary to do the conversion. Inside the ConvertAll function, the code iterates thru each of the values in the input array and passes then to the delegate. The value returned by the delegate is then stored into an output array. The output array is returned to the user once all values are converted.
using ProxyMetaData = TRIMBrokerASMXProxy.ASMXProxy.MetaData;
ProxyMetaData[] convertedArray = Array.ConvertAll<MetaData, ProxyMetaData>(utilArray,
delegate(MetaData metaData)
{
ProxyMetaData returnValue = new ProxyMetaData();
returnValue.Name = metaData.Name;
returnValue.Value = metaData.Value;
return returnValue;
});

Categories

Resources