C# elegant way to assign properties values rather then duplication - c#

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.

Related

Issues with appending array to anonymous array - C#

I'm trying to append array to anonymous array and I received this error:
No best type found for implicitly typed-array.
Here is the array I want to append:
var products = myProductList.Select(x => new
{
isAvailable = 0,
photo = x?.ImageUrl
}).ToArray();
Here is the part of the code where I'm trying to append it (my products array) to, so I want to append rest of the array data to productImages anonymous array:
var articles_data = new
{
products = new[]
{
new
{
prodDate = product.GetDate();
prodtOrdNumb = product.OrdinalNumber,
productAmount = product.Amount
}),
productImages = new[] {
new
{
isAvailable = 1,
photo = productFile?.ImageUrl
},
products.ToArray() // HERE I TRIED TO APPEND MY ARRAY
}
}
}
};
As you can see guys I have posted where I've tried to append my array and I've received:
No best type found for implicitly typed-array.
Any kind of help would be awesome!
Thanks!

How do I add items to ASINList list?

I am trying out the Amazon MWS samples. How do I initialise request.ASINList with a list of ASINs?
My ASINs are in strings.
// Create a request.
GetLowestOfferListingsForASINRequest request = new GetLowestOfferListingsForASINRequest();
string sellerId = "example";
request.SellerId = sellerId;
string mwsAuthToken = "example";
request.MWSAuthToken = mwsAuthToken;
string marketplaceId = "example";
request.MarketplaceId = marketplaceId;
ASINListType asinList = new ASINListType();
request.ASINList = asinList;
string itemCondition = "example";
request.ItemCondition = itemCondition;
bool excludeMe = true;
request.ExcludeMe = excludeMe;
return this.client.GetLowestOfferListingsForASIN(request);
I can't seem to implicitly or explicitly cast a list or array of strings to ASINListType.
Don't know c# but in PHP you have to create an object of class "MarketplaceWebServiceProducts_Model_ASINListType"
e.g.
$asin_list = new MarketplaceWebServiceProducts_Model_ASINListType();
$asin_list->setASIN($asin_array);
$request->setASINList($asin_list);
Your request.ASINList needs to be assigned to an ASINListType. So instantiate that object, and assign your ASINs to it's ASIN property. This is just one way of doing it, but I typically do it very quickly this way:
var asinListType = new ASINListType();
asinListType.ASIN = new List<string> { "B00005TQI7", "B00AVO5XRK", etc, etc };
request.ASINList = asinListType;

Refactor to smaller function, how?

I have a function that loads a large selectlist for ASP.NET MVC.
This functions has a methodsize of 354 rows.
I want to refactor to more functions or to a local field so that each function will be less than 40 lines.
Here is the code snippet:
public static SelectList CreateShutterSpeedList()
{
var shutterSpeedList = new List<CameraSettingItem>();
var secNotationPostfix = "\"";
shutterSpeedList.Add(new CameraSettingItem
{
Id = ShutterSpeedDefaultValue,
Description = string.Empty
});
shutterSpeedList.Add(new CameraSettingItem
{
Id = 1,
Description = "30" + secNotationPostfix
});
etc
Maybe a private list as a variable ? Or loading from file ? Or else...?
If IDs above ShutterSpeedDefaultValue are assigned sequentially, you could create an array of descriptions first, and then convert it to CameraSettingItem list with LINQ:
var descriptions = new[] {
string.Empty
, "30" + secNotationPostfix
, ...
};
shutterSpeedList = descriptions
.Select((d,i) => new CameraSettingItem {
Id = i==0 ? ShutterSpeedDefaultValue : i
, Description = d
})
.ToList();
You could also create a list of CameraSettingItems outside of your method's body, like this:
private const string secNotationPostfix = "\"";
private static IList<CameraSettingItem> shutterSpeedList = new List<CameraSettingItem> {
new CameraSettingItem {
Id = ShutterSpeedDefaultValue,
Description = string.Empty
},
new CameraSettingItem {
Id = 1,
Description = "30" + secNotationPostfix
},
...
};
public static SelectList CreateShutterSpeedList() {
return new SelectList(shutterSpeedList, "Id", "Description");
}
You can store items that you need in JSON or XML files and deserialize them when you need using JavaScriptSerializer or Json.NET for example:
public static SelectList CreateShutterSpeedList(
{
var json = File.ReadAllText(#"\ShutterSpeedList.json");
var shutterSpeedList = JsonConvert.DeserializeObject<List<CameraSettingItem>>(json);
// Convert shutterSpeedList to SelectList and return
}
Alternatively you can reduce number of lines by using collection initializer (as #dasblinkenlight pointed out) and constructors with optional parameters/object initializers if you have access to CameraSettingItem code:
public static SelectList CreateShutterSpeedList()
{
var secNotationPostfix = "\"";
var shutterSpeedList = new List<CameraSettingItem>
{
new CameraSettingItem(id: ShutterSpeedDefaultValue),
new CameraSettingItem(id: 1, description: "30" + secNotationPostfix),
...
};
// Convert shutterSpeedList to SelectList and return
}

Method that returning anonymous object

I have code parts like that:
var #object =
new
{
val = "SUCCESS",
stuff = new
{
stuff1 = model.Stuff1,
stuff2 = model.Stuff2
}
};
return Json(#object, JsonRequestBehavior.AllowGet);
var #object =
new
{
val = "SUCCESS"
};
return Json(#object, JsonRequestBehavior.AllowGet);
var #object =
new
{
val = "ERROR",
details = "Details"
};
return Json(#object, JsonRequestBehavior.AllowGet);
For me it is looking like kind of repetitive code that should be fixed.
I want to refactor that code so I can have something like that:
var #object = GetResult("SUCCESS", object myobj)
return Json(#object, JsonRequestBehavior.AllowGet);
What is the best practice of doing this?
Looks like you're interested in generating properties to anonymous types and assigning values to those properies in runtime.
There's a post here that shows you how to dynamically create classes but it seems like you will have to work pretty hard to get where you want.
Why not generate JSON strings from the different type of objects and the merge it to one JSON string?
string val = "SUCCESS";
var stuff = new
{
stuff1 = "some string",
stuff2 = "4324"
};
string json = new JavaScriptSerializer().Serialize(
new {val, stuff}
);
{"val":"SUCCESS","stuff":{"stuff1":"some string","stuff2":"4324"}}

How to add value into my combobox options in c#?

I have combobox in my windows forms app and I want it to have values on particular options.
Now I can only put an option, and when I choose it - I can get it via
combobox.text
My target is to list filenames in combobox and have paths to them in values.
Example: Text is= "option1" value which it contains is = "value1", how to do it?
I saw a few topics about it, but they are about 2 years old, maybe something changed, cause these solutions were not so friendly : ]
UPDATE
I've got one issue with your solution, Mahmoud Gamal : )
I'm doing it this way:
List<Foo> combo3data = new List<Foo>();
categories = Directory.GetDirectories(#"C:\banners\categories\");
// There are 3 different paths in categories[] array (category1, category2 and 3)
Foo categoryInsert = new Foo();
foreach (string s in categories)
{
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}
comboBox3.DataSource = combo3data;
comboBox3.ValueMember = "path";
comboBox3.DisplayMember = "name";
After that my comboBox3 has 3 available options (correct) but all of them are the same (same as option #1) - why is that?
You are looking for the two properties:
ValueMember.
DisplayMember.
In your case, you have to set the combobox's ValueMember property to value1 and the DisplayMember property to option1.
Update: The following is an exmple of how you can populate the items of a combobox from list of some entity Foo:
public class Foo(){
public string Id { get; set; }
public string Name { get; set; }
}
var ds = new List<Foo>(){
new Foo { Id = "1", Name = "name1" },
new Foo { Id = "2", Name = "name2" },
new Foo { Id = "3", Name = "name3" },
new Foo { Id = "4", Name = "name4" },
};
comboboxName.DataSource = ds;
comboboxName.ValueMember = "Id";
comboboxName.DisplayMember = "Name";
Update2: That's because you are adding the same object each time. In the following block of your code:
Foo categoryInsert = new Foo();
foreach (string s in categories)
{
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}
Each time The foreach iterate over the categories, all what it does, is changing the same object categoryInsert's values path and name not creating a new one. Thus, you end up with the same object added in each iteration to the combo3data. What you need is create a new Foo object inside the foreach itself each time, i.e: move the Foo categoryInsert = new Foo(); inside the foreach loop. Something like:
foreach (string s in categories)
{
Foo categoryInsert = new Foo();
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}
use comboBox.Text to set or get the text associated with this combobox.
for Values use comboBox.ValueMember for the actual value for the items in the ListControl
or you could also store the values in the comboBox.Tag

Categories