I'm a C# beginner and am struggling a little bit with how classes relate to one another.
I am trying to code up a very simple elevator simulation. I have a class for Elevator:
class Elevator
{
public int currentFloor;
public Elevator()
{
currentFloor = 0;
}
public void ascend()
{
currentFloor++;
}
public void descend()
{
currentFloor--;
}
}
Very simple. This works, I can instantiate a new elevator object and have it go up and down, etc...
Now, I want to create a building object, so I created a new class for Buildings. However, I am now stuck - how do I add variable amounts of elevator objects to my buildings? For example, I might want to instantiate a building with 3 elevators, or another with 5...
I started creating a solutiomn where the building class has a List of elevators I can dynamically add to, but that seems so obtuse. So what I am looking for is something like:
Building office = new Building();
office.elevator1 = new Elevator();
office.elevator2 = new Elevator();
which obviously doesn't work because I don't have elevator1 and elevator2 declared in the Building class. What is the best/cleanest way to accomplish what I am looking to do? Also, what is this called? I Googled a ton of terms - class belongs to another class, instantiating a class from another class, similar terms with object instead of class... I've also looked over some of the elevator simulator code out there, but couldn't find anything dynamic like I'm looking for...
Having a List<Elevator> is quite appropriate here; it describes the real-world model very well.
Perhaps it would be better if it were an Elevator[] (in the sense that perhaps it should not be possible to change the number of installed elevators after the building has been erected), but that's not absolute.
In any case, the collection of elevators should be exposed as a read-only property of appropriate type because it doesn't make sense to swap it with another one.
You can add member of type equal to List<Elevator> nd inject inside constructor
Sample
public class Building
{
private List<Elevator> yourList;
public Building(List<Elevator> value)
{
yourList = value;
}
}
Use case :
var list = new List<Elevator>();
list.Add
.....
var building = new Building(list);
Here's an alternative:
class Building
{
public List<Elevator> Elevators { get; set; }
public Building(params Elevator[] elevators)
{
Elevators = elevators.ToList();
}
}
The you can do:
var building = new Building(new Elevator(), new Elevator(), new Elevator());
And add more later:
building.Elevators.Add(new Elevator());
Depends. Say your building will only ever have one elevator. You'd want to do something like this:
public class Building
{
public Elevator Elevator { get; set; }
}
Then when you create the building like you did in your code above, you can do something like this:
office.Elevator = new Elevator();
You're new to C#, so you may not have really been exposed to Properties yet (more reading). Cliffs on Properties: they're creating a way for you to get and set data about your object. In this example, we're getting/setting the Elevator.
Now, if your building is going to have an unknown amount of elevators, you can't just write properties for Elevator1 to ElevatorInfinity. That's when you'll want to use a collection of some sort. As others have posted in here, you can do this like so:
public class Building
{
public IList<Elevator> Elevators { get; set; }
}
And to add an elevator to your building:
// Make sure you instantiate the list! For practice, you should run this code without instantiating the list, so you can see what happens.
office.Elevators = new List<Elevator>();
office.Elevators.Add(new Elevator());
More reading on IList
I think you can override indexer. Of course, you should backbone it with List. Lists are ok.
namespace Tests_CSharp_Indexer
{
class Elevator
{
}
class Building
{
public class ElevatorList
{
private List<Elevator> elevators = new List<Elevator>();
public Elevator this[int i]
{
get
{
return elevators[i];
}
set
{
if (i == elevators.Count)
{
elevators.Add(value);
}
else
{
elevators[i] = value;
}
}
}
public int Count {
get
{
return elevators.Count;
}
}
}
public readonly ElevatorList Elevators = new ElevatorList();
}
class Program
{
static void Main(string[] args)
{
Building building = new Building();
building.Elevators[0] = new Elevator();
building.Elevators[1] = new Elevator();
building.Elevators[2] = new Elevator();
Console.Out.WriteLine(building.Elevators.Count);
}
}
}
Related
I am in a situation that i have to create an instance without knowing the type at compile time.
My code is liket this:
IEnumerable[] columns = new IEnumerable[5];
columns[0] = new string[]{};
i have to be able to create colums[0] without knowing the type ( which is string in the above example).
I couldn't find a solution to my problem, any suggestion is welcomed.
Thank you in advance.
You can use generics like this:
class MyBusiness<T> where T: new()
{
public List<T> coll { get; set; }
public MyBusiness(){
coll = new List<T>();
}
public void DoSth(){
T t = new T();
coll.Add(t);
}
}
You'll want to take a look into Generics. They allow you to create a class that doesn't need to know what the type is until you use it.
public class Column<T>
{
public T Item { get; set; }
}
So you'd use it in your program like so:
var columns = new IEnumerable<Column<string>>();
I have this piece of code
public class Ticket
{
public string strArticleID { get; set; }
public string strArticleDescription { get; set; }
public decimal decArticlePrice { get; set; }
public decimal decArticleVAT { get; set; }
public decimal decArticuleNetPrice { get; set; }
public decimal decArticleDiscount { get; set; }
public decimal decArticleQuantity { get; set; }
}
public static List<Ticket> _lstCurrentTicket = new List<Ticket>();
That I want so send to an external DLL to get all the lines in _lstCurrentTicket to print a ticket through
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
Ticket ticket = new Ticket();
string strRefID = this.dataGridView1.Rows[i].Cells[0].Value.ToString();
string strDescription = this.dataGridView1.Rows[i].Cells[1].Value.ToString();
decimal decQuantity = (decimal)this.dataGridView1.Rows[i].Cells[2].Value;
decimal decUPrice = (decimal)this.dataGridView1.Rows[i].Cells[3].Value;
decimal decDiscount = Convert.ToDecimal(this.dataGridView1.Rows[i].Cells[4].Value.ToString().Substring(0, this.dataGridView1.Rows[i].Cells[4].Value.ToString().Length - 1));
decimal decVAT = Convert.ToDecimal(this.dataGridView1.Rows[i].Cells[5].Value.ToString().Substring(0, this.dataGridView1.Rows[i].Cells[5].Value.ToString().Length - 1));
decimal decGPrice = (decimal)this.dataGridView1.Rows[i].Cells[6].Value;
ticket.strArticleID = strRefID;
ticket.strArticleDescription = strDescription;
ticket.decArticlePrice = decUPrice;
ticket.decArticleVAT = decVAT;
ticket.decArticuleNetPrice = decGPrice;
ticket.decArticleDiscount = decDiscount;
ticket.decArticleQuantity = decQuantity;
_lstCurrentTicket.Add(ticket);
}
TicketPrinting tktPrint = new TicketPrinting ();
//Ticket and copies
tktPrint.PrintTicketFromList(_lstCurrentTicket, 2);
Since it is an external DLL, I thought the easiest way to work with it in target DLL was
public void PrintTicketFromList<T>(List<T> lstArticles, short intCopies)
{
foreach (var prop in lstArticles.GetType().GetProperties())
{
if (prop.Name == "Item")
{
//Copy external list to local class for printing
}
}...
But I'm stuck there. How can I iterate each property and value from each original class in the list so I can copy it? If I make a breakpoint I can see that the fields and values are correctly passed, but I do not get how to access them so I can do something like creating a local class exactly like the original and clone the list (and if I try it will say local list(Ticket) and passed List(T) are not the same type).
Or how could I copy it if I create an exact class in the target and do something like
public void PrintTicketFromList(object lstArticles, short intCopies)
{
List<TargetDLLTicket> lst =((List<TargetDLLTicket>)lstArticles).ToList(); }
Any thoughts?
It sounds like you have a circular dependency issue. You need to move the types you are sending to your print function to a common assembly (new project) that is then referenced by both the calling project and your print project. Then both projects can access this shared type.
A note about your design. The way you are going about this is probably not good to begin with thus your error. The actual printer function should not have to know anything about the types passed in. A good rule of thumb is to try to make your code as loosly coupled as possible. A better idea is to create an Interface that takes care of writing to the printer canvas (or something like that, you did not provide your printer code so this is a guess) and the printer function can call that method on the incoming object. The printer method should then also only accept that interface as a parameter. This is based on a Visitor pattern. Here is an example.
public interface IPrintable {
void WriteToPrinter(PrinterCanvas canvas);
}
public class Printer {
public void Print(IPrintable somethingToPrint) {
var canvas = getCanvas();
somethingToPrint.WriteToPrinter(canvas);
}
}
If at any point possible you should try to avoid reflection like Igor does in his answer.
But if you really want to use reflection you are currently not inspecting the item but the list of items.
You should try something like (writing this from memory):
public void PrintTicketFromList<T>(List<T> lstArticles, short intCopies)
{
foreach (var item in lstArticles)
{
foreach (var prop in typeof(T).GetProperties())
{
var value = prop.getValue(item);
}
}
}
Instead of List<T> create an interface, ITicket for example and accept List<ITicket>. Using List<T> as a generic whenever you know you only can work with something that is a Ticket is creating an unnecessary wide range of potential inputs. Using an interface allows you to not worry about the concrete implementation, and instead get at only what your dll is concerned with, the contract.
You could put the interface in one of two places, either another external common assembly that both of your assemblies reference, or you could put the interface into your assembly that has the ticket printing logic. Your Ticket class could then implement the interface.
An example of what this could look like:
public interface ITicket
{
//properties and methods you want to have all implementations to contain.
}
public class Ticket : ITicket
{
}
public class LastTicket :ITicket
{
}
public void PrintTicketFromList(List<ITicket> lstArticles, short intCopies)
{
}
I'm newbie in C#. Perhaps this is too simply to resolve but I'm really away of the solution.
I have this class:
public class TestSetups : TabelaCtset
{
public IList<TabelaCtsca> ValSetup { get { return m_valsetup; } }
private static List<TabelaCtsca> m_valsetup;
/// Constructor
public TestSetups(IDefinitionList dlist)
: base(dlist)
{
m_valsetup = new List<TabelaCtsca>();
}
}
I have another class called TestCase
public class TestCase : TabelaCttes
{
public IList<TestSetups> Setups { get { return m_setups; } }
private List<TestSetups> m_setups;
...
testcase.m_setups = new List<TestSetups>();
defs = gdl.GetDefinitions(testcase);
while (defs.MoveNext())
{
TestSetups testsetup = new TestSetups(defs);
IDefinitionList valsetup = gdl.GetDefinitions(testsetup);
{
TabelaCtsca ctsca = new TabelaCtsca(valsetup);
testsetup.ValSetup.Add(ctsca);
}
testcase.Setups.Add(testsetup);
}
return testcase;
...
}
I want to put all ctsca values in a ValSetup list. All works fine, except this line testcase.Setups.Add(testsetup);: I have the the properties of TestSetups class but my ValSetup property is always empty, when my while goes to another iteration.
Sorry for this weird explanation. I'm able to explain in more detail.
Update: In this situation, I store in each TestSetup just the last ValSetup value and not all the ValSetup of each TestSetup.
You've made m_valsetup a static property, but you're re-initializing every time you create a new instance of TestSetups. If you want it to be a shared list across all instances of TestSetups, then you could use a property initializer like this:
private static List<TabelaCtsca> m_valsetup = new List<TabelaCtsca>();
And remove the initialization of it in the constructor.
If you didn't intend for the list to be shared, then just remove the static keyword from its definition.
I have an Ability class which looks like this
L1.
public class Ability
{
public int Id { get; set; }
public string Name {get; set;}
}
There are also many more enumlike classes that have Id and Name. So im writing Generic class to have less work later with them.
L2.
public class EnumRepository<TEnum>where TEnum : class
{ ... }
One method od said class looks like this:
L3.
public IEnumerable<SelectListItem> ToSelectListItem(
Expression<Func<TEnum, IEnumerable<Tuple<string, int>>>> text = null)
{
IQueryable<TEnum> query = dbSet;
var ret = new List<SelectListItem>();
if (text != null)
{
var res = query.SelectMany(text);
foreach (var tuple in res)
{
ret.Add(new SelectListItem()
{
Text = tuple.Item1,
Value = tuple.Item2.ToString()
});
}
}
return ret;
}
But I wore sth that I dont know how to use...
L4.
ret.Abilities = _unitOfWork.AbilityRepository
.ToSelectListItem( !what goes here?! )
Here are my questions:
What to put into metod argument in L4. to make it work?
Is there better way to do this?
Is it worth to do it?
In my old aproach I wrote ToSelectListItems in each class of this type. And using it was simple, like this ret.Abilities = Ability.ToSelectListItems() <- static method. But I had to do write this code in every class = hard to maintain and dumb way of doing things.
Assuming I understand your problem correctly, here goes:
What to put into metod argument in L4. to make it work?
Assuming for some reason you want to go ahead with your setup (please see below), you'd have to do something along those lines:
ret.Abilities =
_unitOfWork.AbilityRepository
.ToSelectListItem(item => new[] { new Tuple<String, int> (
(YourAbilityClass)item.Id,
(YourAbilityClass)item.Name)) };
which is slightly counterproductive, as you'd need to maintain part of your repository logic in every call.
Is there better way to do this?
Define better :). The way I would approach is as follows:
1) Define a new base class for all your entities, something like
public class BaseClass
{
public int Id { get; set; }
public String Name { get; set; }
}
and have all your relevant entities inherit from it:
public class Ability : BaseClass
{
}
(alternatively use a common interface - that depends on your design, so I can't make an informed suggestion here)
2) Then constraint your repositories to use BaseClass, like so:
public class EnumRepository<TEnum>where TEnum : BaseClass { ... }
3) Finally you can have
public IEnumerable<SelectListItem> ToSelectListItem()
{
return dbSet.Select(bc => new SelectListItem()
{
Text = bc.Name,
Value = bc.Id.ToString()
})
.ToArray();
}
and call it like so:
ret.Abilities = _unitOfWork.AbilityRepository.ToSelectListItem();
Is it worth to do it?
It's always hard to make fool-proof comments against someone else's design, if we're only shown a very small percent of it. Make your own decision - I do believe my suggestion might be a bit simpler in the long run, assuming it fits your needs.
This is probably a simple question. Suppose I have a object called Users and it contains a lot of protected variables.
Inside that Users class I have a method that creates a temporary Users object, does something with it, and if successful, transfers all the variables from the temp Users object into the one I have.
Is there some fast way to transfer all the variables from one Users object into another Users object without doing this using C#?
this.FirstName = temp.FirstName;
this.LastName = temp.LastName;
........75 variables later......
this.FavoriteColor = temp.FavoriteColor
A better approach is to implement the IClonable interface. But you'll find it doesn't save you a lot of work.
You should check out cloning in C#.
Deep cloning objects
I think serializing and then deserializing an object will create a new object instance. This should be identical to the former object.
A better solution might be to move whatever this method is outside of your class, and then just assign the temp user object to your main user object reference like so:
_User = tmpUser;
sparing you the 75 lines of code. Whenever I have a class creating an instance of itself inside one of its own methods, I always like to blink a couple of times and make sure I really need to be doing that.
There's always the reflection option. Something substantially similar to this:
public static void Copy(object source, object target)
{
foreach (System.Reflection.PropertyInfo pi in source.GetType().GetProperties())
{
System.Reflection.PropertyInfo tpi = target.GetType().GetProperty(pi.Name);
if (tpi != null && tpi.PropertyType.IsAssignableFrom(pi.PropertyType))
{
tpi.SetValue(target, pi.GetValue(source, null), null);
}
}
}
Doesn't require the source and the target to have any relation what-so-ever, just a name and an IsAssignable check. It has the interesting side effects if you're using reference types anywhere, but for the kind of situation you just described, this isn't a bad option to explore.
class sourceTester
{
public bool Hello { get; set; }
public string World { get; set; }
public int Foo { get; set; }
public List<object> Bar { get; set; }
}
class targetTester
{
public int Hello {get; set;}
public string World { get; set; }
public double Foo { get; set; }
public List<object> Bar { get; set; }
}
static void Main(string[] args)
{
sourceTester src = new sourceTester {
Hello = true,
World = "Testing",
Foo = 123,
Bar = new List<object>()
};
targetTester tgt = new targetTester();
Copy(src, tgt);
//Immediate Window shows the following:
//tgt.Hello
//0
//tgt.World
//"Testing"
//tgt.Foo
//0.0
//tgt.Bar
//Count = 0
//src.Bar.GetHashCode()
//59129387
//tgt.Bar.GetHashCode()
//59129387
}