I am relatively new to C# and I would like to create a list of generic objects.
Here is how I try to do it:
I create a base class:
public class BaseClass
{
}
And I inherit a generic class from the base class:
public class GenericClass<T> : BaseClass where T: struct
{
public T data;
public GenericClass(T value)
{
data = value;
}
public T doSomething()
{
return (T)(data * (dynamic)0.826f);
}
}
Then I can create a list of base class:
List<BaseClass> ListOfGenericClasses = new List<BaseClass>();
And I can add instances of the inherited geneic class:
ListOfGenericClasses.Add(new GenericClass<int>(100));
ListOfGenericClasses.Add(new GenericClass<byte>(101));
ListOfGenericClasses.Add(new GenericClass<float>(10.1f));
ListOfGenericClasses.Add(new GenericClass<double>(100.10));
ListOfGenericClasses.Add(new GenericClass<ulong>(9999999999));
ListOfGenericClasses.Add(new GenericClass<long>(-9999999999));
ListOfGenericClasses.Add(new GenericClass<uint>(62389));
ListOfGenericClasses.Add(new GenericClass<sbyte>(-103));
I also can invoke each objects method:
string s = "";
s += ((GenericClass<int>)(ListOfGenericClasses[0])).doSomething() + " # ";
s += ((GenericClass<byte>)(ListOfGenericClasses[1])).doSomething() + " # ";
s += ((GenericClass<float>)(ListOfGenericClasses[2])).doSomething() + " # ";
s += ((GenericClass<double>)(ListOfGenericClasses[3])).doSomething() + " # ";
s += ((GenericClass<ulong>)(ListOfGenericClasses[4])).doSomething() + " # ";
s += ((GenericClass<long>)(ListOfGenericClasses[5])).doSomething() + " # ";
s += ((GenericClass<uint>)(ListOfGenericClasses[6])).doSomething() + " # ";
s += ((GenericClass<sbyte>)(ListOfGenericClasses[7])).doSomething();
MessageBox.Show(s);
And here comes the question: how do I get the value of each instance in the list generally?
I try to do something like this:
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ((GenericClass<ListOfGenericClasses[i].GetType().GetGenericArguments()[0]>)(ListOfGenericClasses[i])).dosdoSomething() + " # ";
}
MessageBox.Show(s);
I have the following error message: "Using the generic type 'GenericClass requires 1 type argument'"
EDIT: sorry guys I could have been more precize when asking my question: my point was not to use the return value to build a string it was just for seeing the result on screen
Any help is much apreciated,
Thanks in advance
I'd approach it in a slightly different way:
public class BaseClass
{
public virtual string DoSomethingToString() { throw new NotImplementedException(); }
}
Then you'd implement your derived class as follows:
public class GenericClass<T> : BaseClass where T: struct
{
public T data;
public GenericClass(T value)
{
data = value;
}
public T DoSomething()
{
return (T)(data * (dynamic)0.826f);
}
public override string DoSomethingToString()
{
return DoSomething().ToString();
}
}
Now you can iterate List<BaseClass> and directly call each element's DoSomethingToString() method.
Does this do what you want?
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
Type type = ListOfGenericClasses[i].GetType();
dynamic d = Convert.ChangeType(ListOfGenericClasses[i], type);
s += d.doSomething() + " # ";
}
It looks like you are trying to implement a union type. I am sure there must be better ways than this.
Should you use Generics? I re-wrote your app and solved the problem by removing Generics
public class GenericClass : BaseClass
{
public object data;
public GenericClass(object value)
{
this.data = value;
}
public object doSomething()
{
return (object)(this.data * (dynamic)0.826f);
}
}
Then I did it:
for (var i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ListOfGenericClasses[i].doSomething() + " # ";
}
You would need to use reflection to get the type and then from that get the method which you can then invoke:
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ListOfGenericClasses[i].GetType()
.GetMethod("doSomething")
.Invoke(ListOfGenericClasses[i], null);
}
However, I would recommend you take the approach as suggested by #corak in the comments and by #InBetween in their answer and create a virtual method in BaseClass and override it in GenericClass.
First use stringBuilder to concat strings, you can cast your object to dynamic to invoke the method you need dynamically:
var stringbuilder = new StringBuilder();
foreach (var l in ListOfGenericClasses)
{
var st = (l as dynamic).doSomething() + " # ";
stringbuilder.Append(st);
}
MessageBox.Show(stringbuilder.ToString());
Related
public Program()
{
amount_bike = new ArrayList();
}
public void push(int value)
{
this.amount_bike.Add(value);
}
public int amount_bike_pop()
{
if (this.amount_bike.Count == 0)
{
return -100000;
}
int lastItem = (int)this.amount_bike[this.amount_bike.Count - 1];
this.amount_bike.RemoveAt(this.amount_bike.Count - 1);
return lastItem;
}
public static void Bike_status()
{
bool exit = false;
Program available = new Program();
available.push(0);
available.push(0);
available.push(50);
WriteLine("E-bike available for rent is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Rented E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Broke E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("\n");
WriteLine("Please enter a number: 1 is back to pervoius menu or 0 to Exit");
int input = Convert.ToInt32(ReadLine());
while (exit == false)
{
if (input == 1)
{
Clear();
exit = true;
continue;
}
else if (input == 0)
{
Clear();
Exit();
}
else
{
Clear();
Bike_status();
}
}
}
public static void Add_bike()
{
}
I study data structures and Algorithms. In this code, I keep the value in an ArrayList named "available" in the Bike_status method. I need to pass a value in an ArrayList to the Add_bike method. How do I pass a value from one method to another? Actually, I need to pass valus such as 50 to plus some number that I push in Console.ReadLine.
Try to slow down.at starting point of programming sometimes it's confusing.
How do I pass a value from one method to another?
The simple answer is easy ,you want something to use in the function then in your method(s) you create parameter and pass the things you want to it.
like
//edit method to get int value -> public static void Bike_status()
public static void Bike_status(int value)
//edit when to call
else
{
Clear();
Bike_status(input);//send int value in
}
But really, what is that do you really want to learn?
if it OOP? I recommend you study this
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/
To put it simply you has bicycle shop class separate from main program then use the method in that class
e.g.
//bicycle class
public class Bicycles{
public int ID {get;set;}
pulibc string status {get;set; }
public Bicycles(int p_id, string p_status)
{
ID = p_id;
status=p_status;
}
}
//bicycle shop class
public class BicyclesShop{
public List<Bicycle> available {get;set;} // class member
public BicyclesShop() // go search keyword "constructor"
{
available = new List<Bicycle> ();
}
//other method
public void Add_bike()
{
// I can access available object !
// do anything with this class member(s) !
}
public void Bike_status(int inputVal)
{
// do something with inputVal , change some properties?
}
//other methods
public int amount_bike_pop()
{
return available.Count();
}
public int amount_bike_broken_pop()
{
return available.Where(o=>o.status =="Broken").Count(); // go search linq
}
}
//To use in Main program method
BicyclesShop bs =new BicyclesShop();
bs.available.Add( new Bicycle(1 ,"OK") ); //add bicycle #1 in list
bs.available.Add( new Bicycle(2),"Broken" ); //add bicycle #2 in list
WriteLine("Broke E-bike is : " + bs.amount_bike_broken_pop() + " bikes.");
I have a Class and a Sub Clas
namespace MyCode
{
public class Class1
{
int a = 1;
int b = 2;
public class SubClass1
{
int a = 1;
int b = 2;
}
}
}
Now I need to instantiate each class by string name. I can do this from the class, but not for the subclass.
This works:
var myObj = Activator.CreateInstance(Type.GetType("MyCode." + "Class1"));
But this, dinĀ“t work:
var myObj = Activator.CreateInstance(Type.GetType("MyCode." + "Class1.SubClass1"));
What I need to do for the second option?
Whenever you don't know what a name should be you can see the name by checking typeof(MyCode.Class1.SubClass1).FullName.
When you have a subclass you use the + sign.
var myObj = Activator.CreateInstance(Type.GetType("MyCode." + "Class1+SubClass1"));
var myObj = Activator.CreateInstance(Type.GetType("MyCode.Class1+SubClass1"));
Its + when dealing with nested types, not .
Hi I am a little new in programming in C#, and I am a little stuck. I have tried searching this site, but I have not been successful on finding an answer to my question. I have also tried changing my private to a public but that did not work.
Here is the error message I am getting:
Error 2 Inconsistent accessibility: parameter type 'exam2.location' is
less accessible than method
'exam2.Form1.MoveToANewLocation(exam2.location)'
Here is part of my code:
public Form1()
{
IntializeComponent();
CreateObject();
MoveToANewLocation(livingRoom);
}
private void MoveToANewLocation(location newLocation)
{
currentLocation = newLocation;
comboBox1.Items.Clear();
for (int i = 0; i < currentLocation.Exits.Length; i++)
{
comboBox1.Items.Add(currentLocation.Exits[i].Name);
comboBox1.SelectedIndex = 0;
}
textBox1.Text = currentLocation.Description;
if (currentLocation is IHasExteriorDoor)
{
GoThroughTheDoor.Visible = true;
}
else
{
GoThroughTheDoor.Visible = false;
}
}
abstract class location
{
public location(string name)
{
this.name = name;
}
public location[] Exits;
private string name;
public string Name
{
get { return name; }
}
public virtual string Description
{
get {
string description = "You're standing in the" + name +
". You see exits to the following places: ";
for (int i = 0; i < Exits.Length; i++)
{
description += " " + Exits[i].Name;
if (i != Exits.Length - 1)
description += ",";
}
description += ",";
return description;
}
}
}
Make location class public if it's not public already
You need to declare your class this way:
public abstract class location
{
...
}
As an aside, general code style has classes starting with a capital letter (ie. Location).
C# defaults the accessibility to internal, so having public methods inside the class will cause this error (like your constructor, properties, and virtual method). A good rule of thumb is to always declare classes public unless you know for sure you want everything in them to be internal or lower.
See MSDN for more information on access modifiers.
Consider the following function, it simply generates an Sql UpdateCommand for an Object
public static string UpdateCommand<T>(this T obj,string idPropertyName, List<string> Except = null, List<string> Only = null)
{
List<PropertyInfo> properties = FilterPropertyList<T>(Except, Only);
StringBuilder query = new StringBuilder();
query.Append("UPDATE " + typeof(T).Name + " SET ");
for (int i = 0; i < properties.Count; i++)
{
if (idPropertyName.ToLower() == properties[i].Name.ToLower())
continue;
query.Append("[" + properties[i].Name + "] = #" + properties[i].Name + ",");
}
if (properties.Count > 1)
{
query.Length -= 2;
}
query.Append(" WHERE " + idPropertyName + "=#" + idPropertyName);
return query.ToString();
}
the second parameter is just the property name which refers to the property name that represents the primary key in the Sql table, i was wondering if its possible to represent that property with an attribute that would be available in the property info, this way i wont have to send it as a parameter.
if this was my object
public class SomeObject
{
//add a custom attribute to the id so it would be recognized in the above function without having to send the property name as a parameter
public int id {get;set;}
public string name {get;set}
}
the following is how i use the function with a SomeObject instance
var someObject = new SomeObject();
var someObjectUpdateCommandString = someObject.UpdateCommand<SomeObject>("id");
can i use some built in attributes, or is it better to create my own attribute?
Here is my try, not sure if its write and i cant seem to use it
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class IsPrimaryKey : Attribute
{
public IsPrimaryKey()
{
this.isPrimaryK = true;
}
private bool isPrimaryK;
public virtual bool IsPrimaryK
{
get { return isPrimaryK; }
set { isPrimaryK = value; }
}
}
The name of the attribute class should end with the Attribute suffix.
Generally, it is a good idea to reuse existing annotations, if they have exactly the purpose that you are looking for, and don't pull unnecessary dependencies.
In your case, the System.ComponentModel.DataAnnotations.KeyAttribute attribute, added in .NET 4.0, would probably fulfill the purpose you are looking for.
How could I make this work?:
public class myClass
{
public string first;
public int second;
public string third;
}
public string tester(object param)
{
//Catch the name of what was passed not the value and return it
}
//So:
myClass mC = new myClass();
mC.first = "ok";
mC.second = 12;
mC.third = "ko";
//then would return its type from definition :
tester(mC.first) // would return : "mc.first" or "myClass.first" or "first"
//and
tester(mC.second) // would return : "mc.second" or "myClass.second" or "second"
In the absence of infoof, the best you can do is Tester(() => mC.first) via expression trees...
using System;
using System.Linq.Expressions;
public static class Test
{
static void Main()
{
//So:
myClass mC = new myClass();
mC.first = "ok";
mC.second = 12;
mC.third = "ko";
//then would return its type from definition :
Tester(() => mC.first); // writes "mC.first = ok"
//and
Tester(() => mC.second); // writes "mC.second = 12"
}
static string GetName(Expression expr)
{
if (expr.NodeType == ExpressionType.MemberAccess)
{
var me = (MemberExpression)expr;
string name = me.Member.Name, subExpr = GetName(me.Expression);
return string.IsNullOrEmpty(subExpr)
? name : (subExpr + "." + name);
}
return "";
}
public static void Tester<TValue>(
Expression<Func<TValue>> selector)
{
TValue value = selector.Compile()();
string name = GetName(selector.Body);
Console.WriteLine(name + " = " + value);
}
}
This is not possible. Variable names don't exist in compiled code, so there's no way you can retrieve a variable name at runtime
That's not possible. "param" will have no information on where the value came from.
When calling tester(), a copy of the value in one of the properties is made, so the "link" to the property is lost.