I created a class that's called UserSessionModel; in it I'm storing some data about the user and in particular I'm storing several json strings that are the results of queries and serializations.
I have several methods and properties in UserSessionModel that overall look like this:
public string SomeUserDataInJson1 { get; set; }
public string SomeUserDataInJson2 { get; set; }
.... 3 more properties like this
public int UserID { get; set; }
private void GetSomeUserDataInJson1
{
ObjectData1 TheObjectData1 = new ObjectData1();
UserQueries TheUserQueries = new UserQueries();
JavascriptSerializer TheSerializer = new JavascriptSerializer();
TheObjectData1 = TheUserQueries.GetData1(TheUserID);
this.SomeUserData1InJson = TheSerializer.Serialize(TheObjectData1);
}
This code is repeated 5 times, with the only change being the ObjectData, the name of the query and the property SomeUserData that's getting set.
Is there a way to make this "better" with an interface or some other c# tools?
Thanks.
Ok, lets assume the following regarding to your example: You're having data for processing with queries defined differently per user (userId).
Our data container class... very simple here, contains only a string.
public class Data
{
public string Content { get; set; }
}
Next step, lets have a look at the query... could be using that interface (could use events, for the response but lets keep it simple here).
public interface IQuery
{
Data Process(Data data);
}
You could have a relation to the user by adding the userId to the IQuery interface but I would prefer to have another interface to solve that:
public interface IUserQueryProvider
{
IEnumerable<IQuery> GetQuerysForUser(uint id);
}
This way you can alter your user to query resolving in a seperate place.
You'll have a serializer/converter, too. Ok, lets make an Interface here for serialization of (processed) data.
public interface ISerializer
{
string Serialize(Data data);
}
Now, lets have a look at implementations, first of all the serializer... doesn't do anything magical here and you should fill in the things you need for serialization of objects (JSON, ...)
public class JavascriptSerializer : ISerializer
{
public string Serialize(Data data)
{
return data.Content; //whatever you want do instead for serialization
}
}
Now let us go to our Queries. I assume you're not very familiar with design patterns and you're meaning something like a Command Pattern instead (for processing jobs, see my link in the comments for more info about design pattern). 3 implementations follows as samples:
public class ReplaceQuery : IQuery
{
private readonly string match;
private readonly string text;
public ReplaceQuery(string match, string text)
{
this.match = match;
this.text = text;
}
public Data Process(Data data)
{
return data.Content.Contains(match) ? new Data {Content = data.Content.Replace(match, text)} : null;
}
}
public class GreetingToQuery : IQuery
{
private readonly string greeting;
private readonly string place;
public GreetingToQuery(string greeting, string place)
{
this.greeting = greeting;
this.place = place;
}
public Data Process(Data data)
{
return data.Content.Contains(greeting) ? new Data {Content = data.Content + place + "."} : null;
}
}
public class LineEndingQuery : IQuery
{
public Data Process(Data data)
{
return data.Content.LastIndexOf(".", StringComparison.Ordinal) == data.Content.Length - 1 &&
data.Content.Length > 0
? new Data {Content = "\n"}
: null;
}
}
If we want to resolve which querys belongs to a user we need our IUserQueryProvider implementation. It is nothing more than a dictionary in this case (but could be easyly switched to other implementations).
public class SampleQueryProvider : Dictionary<uint, IEnumerable<IQuery>>, IUserQueryProvider
{
public IEnumerable<IQuery> GetQuerysForUser(uint id)
{
IEnumerable<IQuery> queries;
TryGetValue(id, out queries);
return queries;
}
}
Last but not least... the glue for everything. I added another Interface here for our "generator engine".
public interface IScriptGenerator
{
event Action<string> Script;
void Generate(Data data, IEnumerable<IQuery> queries);
}
To make it more flexible I made the interface/implementation following a design principle introduced by Ralf Westphal called Event Based Components (EBC). Google is your friend if you are interested in this topic.
public class SampleScriptGenerator : IScriptGenerator
{
private readonly ISerializer serializer;
public event Action<string> Script;
public SampleScriptGenerator(ISerializer serializer)
{
this.serializer = serializer;
}
public void Generate(Data data, IEnumerable<IQuery> queries)
{
foreach (string serialized in from query in queries select query.Process(data) into result where result != null select serializer.Serialize(result))
{
OnSerialize(serialized);
}
}
private void OnSerialize(string serialized)
{
var handler = Script;
if (handler != null) handler(serialized);
}
}
And now lets put it all together and let us fly:
static void Main()
{
var generator = new SampleScriptGenerator(new JavascriptSerializer());
generator.Script += Console.Write; // bind to console output here
var queryProvider = new SampleQueryProvider
{
{
1, // user with id 1
new List<IQuery>
{
new ReplaceQuery("<name>", "frenchie"),
new GreetingToQuery("bonjour", "the universe"),
new LineEndingQuery()
}
},
{
2, // user with id 2
new List<IQuery>
{
new ReplaceQuery("<name>", "stegi"),
new GreetingToQuery("hello", "the world"),
new LineEndingQuery()
}
}
};
var data1 = new Data {Content = "My name is <name>."};
var data2 = new Data {Content = "I say hello to "};
var data3 = new Data {Content = "I say bonjour to "};
var data4 = new Data {Content = "."};
// you cold combine data and user query execution into lists and loops, too
generator.Generate(data1, queryProvider.GetQuerysForUser(1));
generator.Generate(data2, queryProvider.GetQuerysForUser(1));
generator.Generate(data3, queryProvider.GetQuerysForUser(1));
generator.Generate(data4, queryProvider.GetQuerysForUser(1));
generator.Generate(data1, queryProvider.GetQuerysForUser(2));
generator.Generate(data2, queryProvider.GetQuerysForUser(2));
generator.Generate(data3, queryProvider.GetQuerysForUser(2));
generator.Generate(data4, queryProvider.GetQuerysForUser(2));
Console.ReadKey();
}
}
You should see something like:
My name is frenchie.
I say bonjour to the universe.
My name is stegi.
I say hello to the world.
As your homework... try to add your own query implementation and data to process. How would you add recursion here? ;-)
Firstly you should definitely use a List<string> or string[]. Then you can increase code space, and extensibility. You can loop through and load data into the list like your doing there. Another thing, did you mean TheQueries by TheUserQueries, as I can't see the latter declared or the former used.
If you ever find yourself creating more than two similar property like you have done, you should probably use a List.
Secondly, the point of an interface is to force an object to implement certain methods etc. that can then be called and accessed in other classes. If that will help you, then you can put your method in an interface. Otherwise there's really no point.
Related
I would like to use the value of MarketSymbol property of my Order class to call methods inside my Market class,
Order class is:
public class Order
{
public string MarketSymbol { get; set; }
}
MarketSymbol would exactly be either ETH_USDT or BTC_USDT.
which are the exact instances of Market class,
var ETH_USDT = new Market();
var BTC_USDT = new Market();
so while trying to call a method inside Market which is:
public class Market
{
public Market()
{
// some code
}
public SimpleMethod()
{
// some code
}
}
I want to use the value of MarketSymbol to call the methods inside Market class
this is because I don't want to use a switch case or multiple if conditions,
I also would like to know if it's wrong to do this
If I understand correctly, I think you could make a dictionary of Markets, where the key is a string.
Consider the example:
// Your class with some functions
public class Market
{
public Market()
{
}
public void SomeMethod()
{
}
}
Create your Market objects and populate a dictionary. Here you can use the string you wanted to use for MarketSymbol:
Market BTC_USDT = new Market();
Market ETH_USDT = new Market();
Dictionary<string, Market> Markets = new Dictionary<string, Market>();
Markets.Add("BTC_USDT", BTC_USDT);
Markets.Add("ETH_USDT", ETH_USDT);
Now you can access all of the markets in your dictionary, by using that string as an indexer, no need for a case or whatever:
Markets["BTC_USDT"].SomeMethod();
I'm working with C#. I have a Employee class and I'm getting employee data from a URL then I created a list named EmpList in another class which is being populated with that information. I'm not getting the location of each employee so I want to hard code the location by making a set location function in Employee class.
The name 'EmpList' does not exist in the current context.
I've tried to make setLocation function in CreateEmpList function and I got no error but location was empty.
I know I'm probably doing something silly but I really need some help here. I really appreciate that.
Thankyou.
This is my employee class.
public class Employee
{
public string Name { get; set; }
public string Email { get; set; }
public Guid ID { get; set; }
public string Location { get; set; }
public void SetLocation()
{
foreach (var item in EmpList) // I'm getting error here
{
if (item.Email == "abc#gmail.com")
{
item.Location = "US";
}
}
And here I'm populating the list in another class.
private List<Employee> EmpList = null;
private void CreateEmpList(SPHttpClient client)
{
List<Employee> SortedList = new List<Employee>();
JObject jsondata = client.ExecuteJson(UriResources);
string strjsondata = jsondata.First.First.First.First.ToString();
JArray jsonArray = JArray.Parse(strjsondata);
foreach (var item in jsonArray) // Creating master resources list
{
ResourcesExcemptList.ForEach(i => i.ToLower());
if(!ResourcesExcemptList.Contains(item["ResourceEmailAddress"].
ToString().ToLower()))
{
if (Boolean.Parse(item["ResourceIsActive"].ToString()))
{
Employee emp = new Employee();
emp.ID = (Guid)item["ResourceId"];
emp.Email = item["ResourceEmailAddress"].ToString();
emp.Name = item["ResourceName"].ToString();
emp.Practice = item["ResourceGroup"].ToString();
emp.ApproverID =
(Guid)item["ResourceTimesheetManageId"];
SortedList.Add(emp);
}
}
}
EmpList= SortedList.OrderBy(o => o.Name).ToList();
//private void setLocation(){ }
}
The direct answer to your question
The main issue here is that you're not understanding how object oriented code works. You're not using this, and you seem to be confused when the class method will be executed and what that means.
Oddly, when in a class method, you still expect that you need to look through the list to find the correct object. That's the opposite of how you should approach it.
When an object's class method is being executed, you obviously already have found the object whose method you want to call. Because otherwise you wouldn't have been able to call that object's class method.
So what you need to do here is to iterate over the list before you call the object's class method, not after. Your Employee class:
public void SetLocation()
{
this.Location = "US";
}
And then:
private void CreateEmpList(SPHttpClient client)
{
// the rest of the code
EmpList = SortedList.OrderBy(o => o.Name).ToList();
foreach(var employee in EmpList)
{
employee.SetLocation();
}
}
Footnote
Your question shows a basic confusion on OOP principles, but the code itself shows a different level of grasp on OOP principles. I suspect that you didn't write this code yourself, but a colleague did.
I'm mentioning this because I noticed the comment in your example code:
//private void setLocation(){ }
Notice how its signature is that of a method definition, not that of a method call!
What I think has happened is that your colleague annotated the code and placed a reminder for you to create a method, and you've ended up implementing this method in the Employee class instead of in the other class (the one with the CreateEmpList method in it).
Creating the method in the other class makes a lot more sense than putting it in the Employee class. Something along the lines of:
public void SetLocation(Employee employee)
{
employee.Location = "US";
}
One possible solution, based on my comments:
Declare EmpList as:
public List<Employee> EmpList { get; private set;}
Then in your Employee class:
public void SetLocation()
{
var otherClassObj = new otherClassObj(); // Or perhaps some other way of getting the object of the other class.
otherClassObj.CreateEmpList(client); // You may have to change this.
foreach (var item in otherClassObj.EmpList)
{
if (item.Email == "abc#gmail.com")
{
item.Location = "US";
}
}
}
If your main concern is set location value and if empty then set hardcode value then consider this solution:
private string _location;
public string Location
{
get { return _location; }
set
{
if (string.IsNullOrEmpty(value))
{
_location = "US";
}
else
{
_location = value;
}
}
}
To answer your question: public void SetLocation(List<Employee> EmpList) allows the code inside SetLocation() to access the list object (passed by reference) but I doubt this is what you really want to do. (No offense;-)
Your logic isn't clear but surely within CreateEmpList(),
emp.Email = ...
if (emp.Email...) emp.Location = "..."
or within Employee, something like
public string Email { get {} set { Email = value; if (value...) Location = "..."; } }
I am calling a class (Usercontrol) by passing some parameters in its constructor. I'm also saving class instance in a list to perform some custom operations..
// In a Main Class
private List<Point> _pList= new List<Point>(); // Point is a UserControl
private void function(header, tx, rx)
{
Point pt= new Point(header, tx, rx); // all parameters are string and values are dynamic for each class instance
// some operations
_pList.add(pt);
}
In Somewhere in the same class I want to access some special instance of class by checking its parameters. But I don't know how to extract parameters of class by it's instance.
Here is a Pseudo-Code what I want
foreach(var pt in _pList)
{
string header= "something";
string tx = "tx1";
string rx = "rx1";
if(pt.parameter[1]=header && .... ) // just a Pseudo-Code
{
// some tasks
}
}
Kindly guide me how to achieve this.. Thank You
I assume your Point looks -
public class Point
{
public string Header{get;set;}
public string Tx {get;set;}
public string Rx {get;set;}
Public Point(string header,string tx,string rx)
{
Header=header;
Tx=tx;
Rx=rx;
}
}
Your code remain the same of creating the objects and adding it to list.
From your Pseudo-Code, update this to -
foreach(var pt in _pList)
{
string header= "something";
string tx = "tx1";
string rx = "rx1";
if(pt.Header==header && pt.Tx==tx && pt.Rx==rx) // just a Pseudo-Code
{
// some tasks
}
Above is simple change you can make to your code.
Although it suggest your are doing something fishy... as a last resort, you can store them at a place you can access them.
e.g:
public class PointContainer
{
public Point point {get;set;}
public string header {get;set;}
public string tx{get;set;}
//etc
}
And use it in your list:
//first create the container:
var pc = new PointContainer() { /* initialize variables */ };
//and put it in your list
_pList.Add(pc);
//your will contain the combination of points and parameters
Normally, you would be able to gain access to the variables you passed through the object itself:
var point = new Point(header);
var header = point.Header; //so in your case this public property seems missing
I'm working on a testing platform app for students. Since the question can have one or multiple correct answers, I need radio buttons/checkboxes for selecting the right one(s). I would like to implement an abstract class with an Add method. From it, derive two classes, each of them containing an array of RaddioButtons or Checkboxes. Is there a better way to do this than the one listed below? I mean, can the add method be put in the abstract class?
public class AnswerForm
{
public static int no;
public AnswerForm()
{
no=0;
}
}
public class RadioButtonClass:AnswerForm
{
RadioButton[] vector;
public void Add(RadioButton rbutton)
{
vector[no++] = rbutton;
}
}
public class CheckBoxClass : AnswerForm
{
CheckBox[] vector;
public void Add(CheckBox cbox)
{
vector[no++] = cbox;
}
}
I also have two vectors in which I put a fixed number of elements, RadioButtons and Checkboxes. These elements exist in the Windows Form Form1.cs[design]. What I would like to do is pass one an element of type AnswerForm to a function and in the function, based on what type of question I have, allocate memory to my AnswerForm object for one of the derived classes. Also, it might be easier if the Add method would have as parameter a s string, and vector[no++].Text=s;
The prototype of the function:
public void readQuestions(RichTextBox richTextBox, AnswerForm answerForm)
Here I'm parsing an XML file and put the objects in a List. The XML contains Questions, each having a type(multiple or single answer), the text which goes to the richTextBox, and the answers. Next i'm looping through the question list and check question's type. If multiple answers, then put each answer in a CheckBox.Text. Else, put it in a RadioButton.Text. Before assigning the text to each WinForm element, I would like to allocate the corresponding object type(RadioButtonClass or CheckBoxClass) and then use the add method for each answer of the current question. That is why I thought of inheritance, abstractization an polymorphism.
This is how it look like now:
public void readQuestions(RichTextBox richTextBox, AnswerForm answerForm)
{
var file = XDocument.Load("QuestionsTest.xml");
var subject = new Subject();
subject.Name = (string)file.Root.Attribute("Subject");
var questions = from question in file.Root.Elements("Question")
select new Question
{
NumberOfCorrectAnswers=(int)question.Attribute("NumberOfAnswers"),
Text = (string)question.Element("Text"),
Answers = new List<Answer>(
from answers in question.Element("Answers").Elements("Answer")
select new Answer
{
Text = (string)answers
})
};
using (var db = new TestingPlatformContext())
{
db.Subjects.Add(subject);
foreach (var question in questions)
{
//Console.WriteLine("Subject: {0}\n Text: {1}", question.Subject, question.Text);
richTextBox.Text = question.Text;
//db.Questions.Add(question);
foreach (var answer in question.Answers)
//Console.WriteLine("Answer: {0}", answer.Text);
if (question.NumberOfCorrectAnswers != 1)
{
answerForm = new CheckBoxClass();
answerForm.Add(answer.Text);
//db.Answers.Add(answer);
}
else
{
answerForm = new RadioButtonClass();
answerForm.Add(answer.Text);
}
}
}
}
Yes, you can move the Add() method to parent class, using generic:
public class AnswerForm<T>
{
private readonly IList<T> _list;
public AnswerForm()
{
_list = new List<T>();
}
public void Add(T button)
{
_list.Add(button);
}
}
public class RadioButtonClass:AnswerForm<RadioButton>
{
}
public class CheckBoxClass : AnswerForm<CheckBox>
{
}
I made a few changes:
- Use list instead of array, it's more flexible in this case
- Use generic in parent class AnswerForm
A solution, much simple, would be like this:
public class AnswerForm
{
public static int no;
private RadioButton[] rbuttons;
private Checkbox[] checkboxes;
public AnswerForm()
{
no=0;
rbuttons = new RadioButton[]
{
radioButton1,radioButton2,radioButton3,radioButton4,radioButton5
};
checkboxes = new CheckBox[]
{
checkBox1,checkBox2,checkBox3,checkBox4,checkBox5,checkBox6
};
}
public void AddRadio(string s)
{
rbuttons[no++].Text=s;
}
public void AddBox(string s)
{
checkboxes[no++].Text=s;
}
}
But this is far from elegant.
I need to determine which object my code is working with at a certain point and write out only the properties specific to that class. I cannot figure out how to do it. I was told I can do it, but I cannot figure it out. Can someone please show me how to determine which object I am working with and write the properties specific to that class only?
I've looked at other questions asked, but am not smart enough to make it fit my example.
Below, I've re-created an example of the code I am working with. I can see all the code, but I am allowed to only work in one method (for this example called "MethodIAmWorkingIn"). Only modifications I am allowed to make are in that method.
public class Program
{
static void Main(string[] args)
{
TestDetailsAndResultsContainer container = new TestDetailsAndResultsContainer();
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.DerivedClass1Prop1 = "DerivedClass1Prop1";
derivedClass1.DerivedClass1Prop2 = "DerivedClass1Prop2";
DerivedClass2 derivedClass2 = new DerivedClass2();
derivedClass2.DerivedClass2Prop1 = "DerivedClass2Prop1";
derivedClass2.DerivedClass2Prop2 = "DerivedClass2Prop2";
container.TestDetails.Add(derivedClass1);
container.TestDetails.Add(derivedClass2);
TestResult testResult = new TestResult();
testResult.TestResultProp1 = "TestResultProp1";
testResult.TestResultProp2 = "TestResultProp2";
container.Data.Add(testResult);
Program p = new Program();
p.MethodIAmWorkingIn(container);
}
private void MethodIAmWorkingIn(TestDetailsAndResultsContainer container)
{
// I need to see if the container variable holds a DerivedClass1 or DerivedClass2 object.
foreach (var result in container.TestDetails)
{
var classINeedToDetermine = container.TestDetails.FirstOrDefault(m => m.TestDetailsProp1 == result.TestDetailsProp1);
if (classINeedToDetermine is DerivedClass1)
{
classINeedToDetermine = result as DerivedClass1;
}
else if (classINeedToDetermine is DerivedClass2)
{
classINeedToDetermine = result as DerivedClass2;
}
// Now I need to use the classINeedToDetermine object and write its specific properties.
// ???????????????????? I am stuck at this point ??????????????????
// I need to write one or the other below. Can this be done?
// If it is DerivedClass1, I need to write out those properties only.
Console.WriteLine(classINeedToDetermine.DerivedClass1Prop1);
Console.WriteLine(classINeedToDetermine.DerivedClass1Prop2);
// OR
// If it is DerivedClass2, I need to write out those properties only.
Console.WriteLine(classINeedToDetermine.DerivedClass2Prop1);
Console.WriteLine(classINeedToDetermine.DerivedClass2Prop2);
}
}
}
public class TestDetailsAndResultsContainer
{
public TestDetailsAndResultsContainer()
{
this.Data = new List<TestResult>();
this.TestDetails = new List<TestDetails>();
}
public List<TestDetails> TestDetails { get; set; }
public List<TestResult> Data { get; set; }
}
public abstract class TestDetails
{
public string TestDetailsProp1 { get; set; }
public string TestDetailsProp2 { get; set; }
}
public class TestResult
{
public string TestResultProp1 { get; set; }
public string TestResultProp2 { get; set; }
}
public class DerivedClass1 : TestDetails
{
public string DerivedClass1Prop1 { get; set; }
public string DerivedClass1Prop2 { get; set; }
}
public class DerivedClass2 : TestDetails
{
public string DerivedClass2Prop1 { get; set; }
public string DerivedClass2Prop2 { get; set; }
}
The as keyword does not do what you think it does.
Your classINeedToDetermine is a variable of type TestDetails. You can assign a subclass instance to it, but you still cannot access that subclasses specific properties via that variable.
You just need some scope:
if (classINeedToDetermine is DerivedClass1)
{
var derived1 = (DerivedClass1)result;
Console.WriteLine(derived1.DerivedClass1Prop1);
// etc
}
else if (classINeedToDetermine is DerivedClass2)
{
var derived2 = (DerivedClass2)result;
Console.WriteLine(derived2.DerivedClass2Prop1);
// etc
}
This kind of thing is not fun to maintain though.
Another way of doing it would be to use polymorphism: Your TestDetails class could define an abstract method called PrintProperties, and all your subclasses could implement it.
Then you just have to call PrintProperties on every object, without worrying about which subclass they are.
I'm not completely sure on what objects mean what here, but it should be something like this:
foreach(var v in result.GetType().GetProperties())
{
if(v.DeclaringType == result.GetType())
{
Console.WriteLine(v.GetValue(result));
}
}
Again, I wasn't totally clear on your usage of classINeedToDetermine versus result, but you can change those as you see so fit. I chose result as my example since classINeedToDetermine was null by that part of your code.
And by the way, this section of your code is redundant. It should be removed for clarity and efficiency.
if (classINeedToDetermine is DerivedClass1)
{
classINeedToDetermine = result as DerivedClass1;
}
else if (classINeedToDetermine is DerivedClass2)
{
classINeedToDetermine = result as DerivedClass2;
}
Edit:
On the other hand, if performance is more important to you than being scalable (read: if you know or have control over all the classes you'll be dealing with), you could use this is section to do something less, I hate to use this word for this, "generic."
if (classINeedToDetermine is DerivedClass1)
{
var typed = (DerivedClass1)result;
Console.WriteLine(typed.DerivedClass1Prop1);
Console.WriteLine(typed.DerivedClass1Prop2);
}
else if (classINeedToDetermine is DerivedClass2)
{
var typed = (DerivedClass2)result;
Console.WriteLine(typed.DerivedClass2Prop1);
Console.WriteLine(typed.DerivedClass2Prop2);
}
You can use Type.GetProperties to get all Properties for your class. Then you need to get the MethodInfo for the Get method via GetMethod.
Once you have the MethodInfo you can call Invoke, passing in your Derived Class. You can write then write the result to the Console.