I am currently creating a class library for an API. Here is my current issue:
The API has support for multi-call functionality in which I can get data for multiple submissions (i.e. a Skin, Model, Script, etc.) all at the same time in the form of an array holding an object for each of the submissions. The link I will be providing is completely for testing purposes as it returns the same submission three times and can be found here.
The goal is to grab the raw JSON data for each object and put it into a string array so that I can go through each of the objects and deserialize them individually. The reason for this is that the api could return any kind of object (as specified above) and this system must adjust to each object that goes through it. Here's the current code:
Program.cs
class Program
{
static WebClient web = new WebClient();
static void Main(string[] args)
{
APICaller ApiManager = new APICaller(web);
Model exampleObject = new Model(3962);
Model exampleObject2 = new Model(3962);
Model exampleObject3 = new Model(3962);
List<Model> SubmissionInstances = new List<Model>() { exampleObject, exampleObject2, exampleObject3 };
int[] IDs = new int[] { exampleObject.itemID, exampleObject2.itemID, exampleObject3.itemID };
string[] fields = new string[] { exampleObject.fields, exampleObject2.fields, exampleObject3.fields };
ApiManager.Data(SubmissionInstances, IDs, fields);
}
}
APICaller.cs
public List<object> Data<T>(List<T> type, int[] itemid, string[] fields)
{
//Same as the first function but supports multi-call
string itemTypes = "";
string itemIDs = "";
string itemFields = "";
string finalURL = "http://api.gamebanana.com/Core/Item/Data?";
int i = 0;
foreach (object obj in type)
{
itemTypes += "&itemtype[]=" + obj.GetType().Name;
types[i] = obj.GetType();
i++;
}
foreach (int ID in itemid)
{
itemIDs += "&itemid[]=" + ID;
}
foreach (string field in fields)
{
itemFields += "&fields[]=" + field;
}
finalURL += itemTypes + itemIDs + itemFields + "&return_object=1";
string[] JSONObjects = JsonConvert.DeserializeObject<string[]>(client.DownloadString(finalURL));
List<object> toReturn = new List<object>();
i = 0;
foreach (string str in JSONObjects)
{
toReturn.Add(DeserializeObject(type[i], str));
i++;
}
return toReturn;
}
public T DeserializeObject<T> (T obj, dynamic JSONObj)
{
return JsonConvert.DeserializeObject<T>(JSONObj);
}
Related
This question already has answers here:
Help someone new to C# variables
(5 answers)
Closed 2 years ago.
In my current application while I have been able to implement the required logic that I need I am really stuck when trying to take off the content from the main method and using it from a different method .
My code is as below,
class Program
{
const string path = #"filePath";
static void Main(string[] args)
{
setUpValues();
}
private static void setUpValues()
{
var Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
string Version = null;
List<string> ListOfSelectedItems= new List<string>();
List<string> TempListOfSelectedItems = new List<string>();
List<string> Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
Console.WriteLine("Version " + Version);
Console.WriteLine();
string SelectedItems= TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
}
}
I want to be able to access the variable string Version , the List of ListOfSelectedItems and the List of channels from outside this method .. I want to use these in another as well . So how can I make these globally accessible ?
Would really appreciate your help on this as I have been stuck here
In order to use variables outside a method, you should declare them as fields of a class. Like this:
class Program
{
const string path = #"filePath";
static deploy Content;
static string Version;
static List<string> ListOfSelectedItems;
static List<string> TempListOfSelectedItems;
static List<string> Channels;
// and others
static void Main(string[] args)
{
setUpValues();
}
private static void setUpValues()
{
Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
Version = null;
ListOfSelectedItems = new List<string>();
TempListOfSelectedItems = new List<string>();
Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
Console.WriteLine("Version " + Version);
Console.WriteLine();
string SelectedItems = TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
}
}
You have to declare those fields as static because they are used in a static method. After the setUpValues finishes running, you can use those fields inside the Main method as well.
Also, this is not related to the question, but the general code convention in C# is to start methods' names with an uppercase letter (so SetUpValues instead of setUpValues) and to start the local variables' names with a lowercase letter (selectedItems instead of SelectedItems). Obviously, it's ultimately up to you how to name things and which code convention to use.
Create a class with properties that you want to access from other places. Instantiate this class in setUpValues and return this.
public class TestClass
{
public TestClass()
{
this.ListOfSelectedItems = new List<string>();
}
public string Version { get; set; }
public List<string> ListOfSelectedItems { get; set; }
}
And then modify your Main method as:
var myObj = setUpValues();
And then Modify setUpValues to return this:
private static TestClass setUpValues()
{
var Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
string Version = null;
List<string> ListOfSelectedItems = new List<string>();
List<string> TempListOfSelectedItems = new List<string>();
List<string> Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
var retObj = new TestClass();
Console.WriteLine("Version " + Version);
Console.WriteLine();
retObj.Version = Version;
string SelectedItems = TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
retObj.ListOfSelectedItems.Add(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
return retObj;
}
i have a list of objects , and each object have a list of dependant objects , i want to write the list in a text file in a tree view form .
i tried doing foreach on the list but i can't all dependencies and the correct levels of objects
//the list of all objects
List<Object> objects;
//object Class
class Object {
string name;
List<Object> depandantObj;
}
the expected result must be writen in text file under the form :
object1:
object2
object3:
object5
object1
object6:
object2
etc...
Recursive method to append a new line for each object with indent:
public string GetText(Object obj, int indentLevel)
{
string text = "";
string indentation = new string(' ', indentLevel * 8);
text += indentation + obj.name;
if (obj.depandantObj != null && obj.depandantObj.Count > 0)
{
indentLevel++;
foreach (Object o in obj.depandantObj)
{
text += Environment.NewLine + GetText(o, indentLevel);
}
}
else
return text;
return text;
}
Call the method for each object in the list and write the text into the text file at the end:
make sure both of the fields (name and depandantObj) in Object class are public
List<Object> objects;
//add items to list
...
if(objects != null)
{
string text = "";
foreach (Object obj in objects)
{
text += GetText(obj, 0);
}
File.WriteAllText(Server.MapPath("~/sample.txt"), text);
}
First create your Objects with nested list forms. For example:
public class MyObject{
// some properties here
}
public class MySecondObject{
List<MyObject> {get; set;}
}
public class MythirdObject{
List<MySecondObject> {get; set;}
}
And when you want to save the data to a file just seriliaze them to json , it will already create a readable json file for you.
// I assume you can create your data or fetch them
var data = List<MyThirdObject> ();
string json = JsonConvert.SerializeObject(_data);
//write string to file
System.IO.File.WriteAllText(#"D:\path.txt", json);
If you don't want json than you can create a recusrive method that add each object to under last one.
Have a look this question for how you can this at this way.
Consider using json, download newtonsoft dll from Nuget.
a code example:
public class MyObject
{
public string Name { get; set; }
}
public class MySecondObject
{
public List<MyObject> DepObj { get; set; } = new List<MyObject>();
}
usage example:
MyObject obj = new MyObject
{
Name = "example"
};
MySecondObject mySecond = new MySecondObject();
mySecond.DepObj.Add(obj);
var data = new List<MySecondObject>
{
mySecond
};
string json = JsonConvert.SerializeObject(data, Formatting.Indented);
System.IO.File.WriteAllText(#"D:\file.txt", json);
File content:
[
{
"DepObj": [
{
"Name": "example"
}
]
}
]
First, let's elaborate initial Object class; I've renamed it (in order not to conflict with System.Object), make fields being public, add a constructor:
class MyObject {
public string name = "";
public List<MyObject> depandantObj = new List<MyObject>();
public MyObject(string value, params MyObject[] dependent) {
name = value;
if (dependent != null)
foreach (var item in dependent)
depandantObj.Add(item);
}
}
Then we can implement an iterator, IEnumerable<string>:
private static IEnumerable<string> MyObjectToTree(IEnumerable<MyObject> roots, int shift = 6) {
if (null == roots)
yield break;
foreach (var root in roots) {
// We don't want infinte loop if objects create a cycle
HashSet<MyObject> completed = new HashSet<MyObject>();
Stack<Tuple<int, MyObject>> agenda = new Stack<Tuple<int, MyObject>>();
agenda.Push(Tuple.Create(0, root));
while (agenda.Any()) {
Tuple<int, MyObject> item = agenda.Pop();
if (!completed.Add(item.Item2))
continue;
List<MyObject> children = item.Item2?.depandantObj ?? new List<MyObject>();
children.Reverse();
yield return $"{new string(' ', shift * item.Item1)}{item.Item2?.name}{(children.Any() ? ":" : "")}";
foreach (var child in children)
agenda.Push(Tuple.Create(item.Item1 + 1, child));
}
}
}
Demo:
// I've added the MyObject constructor for this readable creation
List<MyObject> objects = new List<MyObject>() {
new MyObject("object1",
new MyObject("object2"),
new MyObject("object3",
new MyObject("object4"),
new MyObject("object5"))),
new MyObject("object6",
new MyObject("object2")),
};
foreach (string line in MyObjectToTree(objects, 6))
Console.WriteLine(line);
// If you want to write into file:
// File.WriteAllLines(#"c:\MyFile.txt", MyObjectToTree(objects, 6));
Outcome:
object1:
object2
object3:
object4
object5
object6:
object2
In below code, I'm returning each issue details in foreach loop and I have around 150 issues.Eachtime i loop through I'm getting the last values in "returnResulttoReport".
Note: "result" is a JSON string and foreach is getting result as below:
Here is my issue class:
[DataContract]
public class MyIssues
{
public MyIssues()
{
Comments = new List<Comment>();
}
[DataMember(Order = 0)]
public string Key;
[DataMember(Order = 1)]
public List<Comment> Comments;
}
[DataContract]
public class Comment
{
[DataMember(Order = 1)]
public DateTime? Updated;
}
public List<MyIssues> method(string result)
{
RootObject myresult = JsonConvert.DeserializeObject<RootObject>(result);
List<MyIssues> returnResulttoReport = new List<MyIssues>();
foreach (var item in myresult.issues)
{
issueKey = item.key ?? string.Empty;
foreach (var commentitem in item.fields.comment.comments)
{
updated = commentitem.updated ?? string.Empty;
}
}
MyIssues temp1 = new MyIssues{ Comments = new List<Comment>
{
new Comment() {
Updated = updated
}
},
Key = key };
returnResulttoReport.Add(temp1);
return returnResulttoReport;
}
Basically, I wanted to capture each return result before it get lost.
I tried putting it in ArrayList like below:
ArrayList<JiraIssues> sendAllForReport = new ArrayList<JiraIssues>();
I'm getting error: The generic type arraylist can not be used with type arguments. How to resolve this? Is there any other ways to do it?
The problem is that you are reassigning updated without ever reading its value until you finish the loop. Therefore, the last item in the loop is the only one you read. You need to add an item to the list for each iteration in the loop, so the code to do that must be inside the loop rather than after it. Try this instead:
public List<MyIssues> method(string result)
{
RootObject myresult = JsonConvert.DeserializeObject<RootObject>(result);
List<MyIssues> returnResulttoReport = new List<MyIssues>();
foreach (var item in myresult.issues)
{
issueKey = item.key ?? string.Empty;
foreach (var commentitem in item.fields.comment.comments)
{
updated = commentitem.updated ?? string.Empty;
MyIssues temp1 = new MyIssues {
Comments = new List<Comment>
{
new Comment() { Updated = updated }
},
Key = key };
returnResulttoReport.Add(temp1);
}
}
return returnResulttoReport;
}
The fact that updated is declared somewhere else is a terrible code smell. I would do this instead:
public List<MyIssues> method(string result)
{
RootObject myresult = JsonConvert.DeserializeObject<RootObject>(result);
List<MyIssues> returnResulttoReport = new List<MyIssues>();
foreach (var item in myresult.issues)
{
issueKey = item.key ?? string.Empty;
foreach (var commentitem in item.fields.comment.comments)
{
var upd = commentitem.updated ?? string.Empty;
MyIssues temp1 = new MyIssues {
Comments = new List<Comment>
{
new Comment() { Updated = upd }
},
Key = key };
returnResulttoReport.Add(temp1);
}
}
return returnResulttoReport;
}
(I called the variable upd so it would not conflict with other possible uses of updated in some other scope.)
You're looking for the type List<T> - C#'s ArrayList is not a generic type. It's a holdover from the days before generics in .NET.
Sorry if the title does not reflect what I actually want.
I'm creating a generic class for selecting, updating, inserting and deleting dates from and to a database.
Basically, I want a function that gives me back an ObservableCollection<"can be anything"> ==> Where anything is a class and not strings. I would like to know if it is possible to do this, if yes, please,help me how I can achieve this.
this is my starting point:
//class a
public static ObservableCollection<ContactPerson> contactPersons = new ObservableCollection<ContactPerson>();
public static ObservableCollection<ContactPerson> getContactPerson()
{
contactPersons = (ObservableCollection<ContactPerson>)DBConnection.GetDataOutDatabase(typeof(ContactPerson), "Contactpersoon");
return contactPersons;
}
//class b
public static Object GetDataOutDatabase(Type myType,String table)
{
ObservableCollection<Object> objecten = new ObservableCollection<Object>();
string sql = "SELECT * FROM " + table;
DbDataReader reader = Database.GetData(sql);
while (reader.Read())
{
objecten.Add(Create(myType, reader));
}
return objecten;
}
private static Object Create(Type myType, IDataRecord record)
{
PropertyInfo[] myPropertyInfo = myType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < myPropertyInfo.Length; i++)
{
PropertyInfo myPropInfo = (PropertyInfo)myPropertyInfo[i];
String name = myPropInfo.Name;
Type type = myPropInfo.PropertyType;
}
return null;
}
And this is what I ultimately want to get. Is this possible?
//ContactPerson cp = new ContactPerson();
//cp.ID = (record["ID"].ToString());
//cp.Name = record["Name"].ToString();
//cp.Company = record["Company"].ToString();
//cp.JobTitle = new ContactPersonTitle()
//{
// Name = record["JobTitle"].ToString(),
//};
//cp.JobRole = new ContactPersonType()
//{
// Name = record["JobRole"].ToString(),
//};
//cp.City = record["City"].ToString();
//cp.Email = record["Email"].ToString();
//cp.Phone = record["Phone"].ToString();
//cp.Cellphone = record["Cellphone"].ToString();
Many thanks!
You can actually do this with reflection in generic methods.
public class DBConnection
{
public static ObservableCollection<T> GetDataOutDatabase<T>(string table)
{
var objecten = new ObservableCollection<T>();
string sql = "SELECT * FROM " + table;
DbDataReader reader = Database.GetData(sql);
while (reader.Read())
{
objecten.Add(Create<T>(reader));
}
return objecten;
}
public static T Create<T>(IDataRecord record)
{
var properties = typeof(T).GetProperties();
var returnVal = Activator.CreateInstance(typeof(T));
properties.ToList().ForEach(item =>
{
try
{
if (item.PropertyType.IsPrimitive)
{
item.SetValue(returnVal, Convert.ChangeType(record[item.Name].ToString(), item.PropertyType),null);
}
else
{
object[] parameters = {record};
var value =
typeof(DBConnection).GetMethod("Create").MakeGenericMethod(item.PropertyType).Invoke(null, parameters);
item.SetValue(returnVal,value,null);
}
}
catch
{
Write("Property Not Found");
}
});
return (T)returnVal;
}
}
The example above does assume that all properties names match the column names you are retrieving from your database communication. For instance in the ContactPersonTitle above rather than Name you would need to have JobTitle as the property name.
Not as you are currently doing it. You should look into the entity framework which allows translation of database tables datacollections.
have a look at:
http://www.codeproject.com/Articles/363040/An-Introduction-to-Entity-Framework-for-Absolute-B
I want to retrieve object data from an ArrayList;
public class Form1
{
ArrayList list = new ArrayList();
private void OnSockMessage(object sender, SockEventArgs e)
{
Regex MyRegex = new Regex("^[<][A-Za-z]");
if (e.SockMsg != null)
{
string y = e.SockMsg.ToString();
if (MyRegex.IsMatch(y) == true)
{
rrr = y;
string ipdd = SocClient[e.SocketRef].Soc.RemoteEndPoint.ToString();
//serverkey seckey;
list.Add(new serverkey(ipdd,rrr));
}
else
{
string curipadd = SocClient[e.SocketRef].Soc.RemoteEndPoint.ToString();
for (int i = 0; i < list.Count-1; i++)
{
//serverkey pk = list[i] as serverkey;
//string jj = list[i].ToString();
// serverkey pk = new serverkey(list[i].ToString());
/*********************************************
here i want to retrieve data from array list
*********************************************/
string ipadd;
if (curipadd == ipadd )
{
y = DecryptString(e.SockMsg, rrr);
listBox1.Items.Add(txtIP.Text + " <<" + y);
}
}
}
}
public class serverkey : Form1
{
string ipaddress;
string secertkey;
public serverkey(string IPAdd, string Seckey)
{
ipaddress = IPAdd;
secertkey = Seckey;
}
public string ip
{
get { return ipaddress; }
}
public string key
{
get { return secertkey; }
}
You'd be better off using a strongly typed generic List<serverkey> and a foreach loop rather than a for loop. It'll be something like
List<serverkey> list = new List<serverkey>();
//add your items as you already are
foreach(var item in list)
{
item.ip ...// use item as a serverkey
}
Having said that, if you can you use a generic for some reason, use an 'as'
ArrayList list = new ArrayList();
//add your items as you already are
foreach(var item in list)
{
var sk = item as serverkey;
sk.ip ...// use item as a serverkey
}