Edit: In real life i don't have a Book class. This is just an example to be clear. Real problem really needs reflection to solve it.
Suppose that I have some classes:
Book, Apple, Door.
class Book
{
...
public decimal getPrice()
{...}
public string getTitle()
{...}
public decimal getAuthor()
{...}
}
and something same for other classes.
May i call a class method dynamically from a string:
Book myBook = new Book("Title", "Author", 44);
string title = runMethod(myBook, "getTitle");
You can do this via Reflection.
Book myBook = new Book("Title", "Author", 44);
string title = (string) myBook.GetType().GetMethod("getTitle").Invoke(myBook, null);
You can use something like this, using reflection:
class Program
{
static void Main(string[] args)
{
var b = new Book("Book Title", 2342);
Console.WriteLine(CallMethod(b, "GetTitle", "Not Found"));
}
public static K CallMethod<T,K>(T a, string method, K defaultOjb)
{
var t = a.GetType();
var mi = t.GetMethod(method);
if (mi == null) return defaultOjb;
var ret=mi.Invoke(a, new object[] {});
return (K) ret;
}
}
public class Book
{
private readonly string _title;
private readonly decimal _price;
public decimal GetPrice()
{
return _price;
}
public string GetTitle()
{
return _title;
}
public Book(string title, decimal price)
{
_title = title;
_price = price;
}
}
Lookup reflection and MethodInfo. I believe that will lead you down the path you are looking for.
Previous answers are correct in mentioning reflection.
However, unless your true question is very different from your example it's unnecessary.
Judging from your example you could simply call it directly:
string title = mybook.getTitle();
If the point is that you don't know and don't want to care what specific object you're being given you can either use a base class, or an interface.
public interface IProduct
{
string Name { get; }
string Type { get; }
float Price { get; }
}
Make your classes implement IProduct and you're guaranteed that your classes will have implemented the properties or functions you've required, and that they will be public no matter whether you're dealing with "Book", "Apple", or "Door".
public void OutputProductsToConsole(List<IProduct> products)
{
for (int i = 0; i < products.Count; i++)
{
Console.WriteLine(products[i].Name + ": " + products[i].Price);
}
}
It is possible with reflection, but in the example, it would be simpler to just call the method directly:
string title = myBook.getTitle();
You are instantiating your new Book class with the property values. Are you not assigning the values so you can get them back later?
public class Book
{
private string _title;
private decimal _price;
private string _author;
public Book(string title, decimal price, string author);
{
_title = title;
_price = price;
_author = author;
}
public string Title
{
get
{
return _title;
}
}
public decimal Price
{
get
{
return _price;
}
}
public string Author
{
get
{
return _author;
}
}
}
Better yet, if these methods are common to all your classes create an interface and inherit that in your classes.
Related
This question already has answers here:
Return multiple values to a method caller
(28 answers)
Closed 8 years ago.
I have a question in returning two values from a method.
I have a method from which I have to return two values. I did like this.
public string fileName(string rate,out string xmlName,out string xsdName)
{
if(rate=="2013")
{
xmlName="abc";
xsdName="def";
}
if(rate=="2014")
{
xmlName="pqr";
xsdName="xyz";
}
//stmt 1 (Here it is asking to give default values for xmlname and xsdName.But i dont want to give any default values.)
}
Now in another class I have to call this function and assign these values of xmlname and xsdName in that class. How can I do this?
public OtherClass fileName(string rate)
{
OtherClass obj = new OtherClass();
if (rate == "2013")
{
obj.xmlName = "abc";
obj.xsdName = "def";
}
if (rate == "2014")
{
obj.xmlName = "pqr";
obj.xsdName = "xyz";
}
return obj;
}
public class OtherClass
{
public string xmlName { get; set; }
public string xsdName { get; set; }
}
You'd use it like this:
string xmlName;
string xsdName;
fileName("2014", out xmlName, out xsdName);
Your fileName() method can have a return type of void since you're not technically returning anything from the function.
The best concept would be using the Objective-Oriented programming. Create a class that has two properties, xmlName and xsdName. Then return a new instance of the class from the method.
The code below should give you an idea.
Class implementation in file XmlFile.cs
public class XmlFile
{
public string XmlName
{ get; set; }
public string XsdName
{ get: set; }
}
Function implementation:
public XmlFile fileName(string rate)
{
XmlFile file = new XmlFile();
if (rate == "2013")
{
file.XmlName = "abc";
file.XsdName = "def";
}
if (rate == "2014")
{
file.XmlName = "pqr";
file.XsdName = "xyz";
}
return file;
}
Please look at OO programming in detail, you will need it with C#.
Your question is vague, but I'll try my best.
Here's how to call fileName and receive the output for the last two parameters:
string xmlName;
string xsdName;
myInstance.fileName("2014", out xmlName, out xsdName);
I tend to shy away from using out. A better solution is to create a new class that wraps the data:
public class File
{
public File(string fileName, string xmlName, string xsdName)
{
FileName = fileName;
XmlName = xmlName;
XsdName = xsdName;
}
public string FileName
{
get;
private set;
}
public string XmlName
{
get;
private set;
}
public string XsdName
{
get;
private set;
}
}
public class OtherClass
{
public File FileName(string rate)
{
switch (rate)
{
case "2013":
return new File(..., "abc", "def");
case "2014":
return new File(..., "pqr", "xyz");
default:
throw new ArgumentException(String.Format("Unexpected rate '{0}'.", rate)); // Or, simply return null
}
}
}
To call a function with out parameters:
string xmlN;
string xsdN;
var result = fileName("rate value", out xmlN, out xsdN);
But one problem is that you need to assign them before the end of the function.
In this case, setting them to null might be appropriate.
There are several possible ways to do it. First is how you do it - output parameters
string xmlName, xsdName;
filename("xxx", out xmlName, out xsdName);
Second one is to use tuples.
public Tuple<string, string> fileName(string rate)
{
...
return Tuple.Create(xmlName, xsdName)
}
Third one is to define you own class
class XmlInfo
{
public string XmlName {get; set;}
public string XsdName {get; set;}
}
XmlInfo filename(string rate)
{
...
return new XmlInfo() { XmlName = xmlName, XsdName = xsdName };
}
Movie Class
public class Movie
{
#region Properties
public string Name { get { return _name; } set { _name = value; } }
public string Producer { get { return _producer; } set { _producer = value; } }
public int Rating { get { return _rating; } }
public Image Covor { get; set; }
public string Description { get { return _description; } }
public int ReleaseYear { get { return _releaseYear; } set { _releaseYear = value; }}
#endregion
#region Private Fields
private string _name;
private string _producer;
private int _rating;
private string _description;
private int _releaseYear;
#endregion
#region Constructors
public Movie()
{
}
public Movie(string name, int yearRelease)
{
this._name = name;
this._releaseYear = yearRelease;
}
public Movie(string name, int yearRelease, string producer)
{
this._name = name;
this._releaseYear = yearRelease;
this._producer = producer;
}
#endregion
}
My attempt
foreach (DataRow movieRow in MovieTable().AsEnumerable())
{
if (movieRow["Producer"] != DBNull.Value)
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
Producer = (string)movieRow["Producer"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
else
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
}
This is my code so far I'm trying to convert a Table to a List. The only problem is DBNull's.
I would like to update the entire table to a list, this works currently for 2 situations, but I need for the List to contain all the information if it exists. I could create elseif statements to handle every possible scenario but there has to be a way better way to figure out if the type is DBNull and if not set the property correctly.
If there's any confusion tell me what it is and I'll explain further.
One option is to incorporate the null-check into the set-statements wherever you need them, using shorthand code:
Name = (movieRow["Name"] == DBNull.Value) ?
(string)movieRow["Name"] :
string.Empty,
// Producer will be given a value if it exists, or null otherwise:
Producer = (movieRow["Producer"] == DBNull.Value) ?
(string) movieRow["Producer"] :
null,
...
You can replace string.Empty with null or vice versa of course, if that suits you better.
Edit: Just a very basic clarification, since you state you are new to programming: This shorthand notation means "if firstValue is true, return secondValue, otherwise, return thirdValue"
var result = firstValue ? secondValue : thirdValue;
One option: you can check IsNull(column):
Movie movie = new Movie()
{
Name = movieRow.IsNull("Name")
? (string)null : (string)movieRow["Name"],
Producer = movieRow.IsNull("Producer")
? (string)null : (string)movieRow["Producer"],
// etc..
};
movieList.Add(movie);
I am new to C# and am working on classes and understanding them. My problem is I am not understanding how to create a Get to retrieve the private variable _yourname and Set to set the private variable _yourname.
namespace WindowsFormsApplication1
{
class InputClass
{
private string _yourName;
public string _banner;
public virtual void GetInfo();
public InputClass(String _banner)
{
_banner = "Enter your name";
}
}
}
Maybe I am using the wrong function to GetInfo. But I am also wondering when I have the GetInfo if in the () I should write _yourname in it.
In C# there are properties, which have the function of public getter and setter methods in other languages:
class InputClass
{
private string _yourName;
public string _banner;
public InputClass(String _banner)
{
this._banner = _banner;
}
public string YourName
{
get { return _yourName; }
set { _yourName = value; }
}
}
But you can use auto properties, if you want:
class InputClass
{
public InputClass(String _banner)
{
Banner = _banner;
}
public string YourName
{
get; set;
}
public string Banner
{
get; set;
}
}
It sounds like you are trying to provide access to the _yourName field. If so then just use a property
class InputClass {
public string YourName {
get { return _yourName; }
set { _yourName = value; }
}
...
}
Now consumers of InputClass can access it as if it were a read only field.
InputClass ic = ...;
string yourName = ic.YourName;
ic.YourName = "hello";
Note: C# provides a special syntax for simple properties like this which are just meant to be wrappers over private fields. It's named auto-implemented properties
class InputClass {
public string YourName { get; set; }
}
You can override getters and settings using the get and set keywords. For example:
class InputClass
{
private string _yourName;
private string _banner;
public YourName
{
get { return _yourName; }
set { _yourName = value; }
}
public Banner
{
get { return _banner; }
set { _banner = value; }
}
public InputClass(String banner)
{
_banner = banner;
}
}
1.) Use properties instead of members, you get a free accessor (get) and mutator (set).
public string YourName { get; set; }
public string Banner { get; set; }
2.) You can take advantage of the default constructor, and declare it on the fly.
//the old way:
InputClass myClass = new InputClass();
myClass.YourName = "Bob";
myClass.Banner = "Test Banner";
//on the fly:
InputClass myClass = new InputClass()
{
YourName = "Bob",
Banner = "Test Banner"
}
I have this code (which is way simplified from the real code):
public interface IAmount
{
decimal Amount { get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount { get; set; }
}
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
amount.Amount = GetAmount();
}
public static decimal GetAmount()
{
return 12345m;
}
The code works great and the UpdateAmounts ExtensionMethod is used quite frequently throughout the application to apply a penny rounding routine (not like the one in Office Space!)
The problem is I do not like having an IAmount interface with a specific name of the column I need to set (Amount). In a new requirement, I need to update a database entity collection with this routine and the name of the property I need to update is "GrossAmount". Sometimes too it would be nice to update other writable decimal properties in a similar manner.
The problem is that it appears I cannot simple say amount.Field = GetAmount() where the .Field part deals with a different property on the entity. Is it possible somehow? I am not on C# 4.0, so using a dynamic type isn't possible for me yet.
You could do this in a more functional style, something like this:
public class Something
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void UpdateAmounts<T, U>(IEnumerable<T> items, Action<T,U> setter, Func<T, U> getter)
{
foreach (var o in items)
{
setter(o, getter(o));
}
}
public void QuickTest()
{
var s = new [] { new Something() { Amount = 1, OtherAmount = 11 }, new Something() { Amount = 2, OtherAmount = 22 }};
UpdateAmounts(s, (o,v) => o.Amount = v, (o) => o.Amount + 1);
UpdateAmounts(s, (o,v) => o.OtherAmount = v, (o) => o.OtherAmount + 2);
}
What about having a Dictionary-like interface ?
public interface IAmount {
decimal this[string fieldName] { get; set; }
}
Implementation is simply:
public class Money : IAmout {
private Dictionary<string, decimal> _dict;
public decimal this[string fieldName] {
get { return _dict[fieldName]; }
set { _dict[fieldName] = value; }
}
}
(of course, it requires some error checking)
Then, one can write:
Money m = new Money();
m["Amount"] = ...
or
m["GrossAmount"] = ...
Not as nice as dynamic, I agree.
public class SomeAmount : IAmount
{
decimal amount;
public decimal Amount
{
get{return this.amount;}
set{this.amount=value; }
}
}
Not sure how willing you are to screw with your entities, but...
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount { get; set; }
decimal IAmount.Amount
{
get { return GrossAmount; }
set { GrossAmount = value; }
}
}
This hides the Amount implementation of your entity in any context that it's not directly used as an IAmount, while still allowing it to function as an IAmount.
You could hide the Field property, like this:
public interface IAmount
{
decimal Field
{ get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount
{ get; set; }
decimal IAmount.Field
{
get { return Amount; }
set { Amount = value; }
}
}
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount
{ get; set; }
decimal IAmount.Field
{
get { return GrossAmount; }
set { GrossAmount= value; }
}
}
Casting the object to IAmount reveals the Field for your purposes. Otherwise, Field is hidden in the designer and Amount (or GrossAmount) is what you'll be working with.
You could also use reflection in order to apply your rounding on every decimal inside your type.
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
{
var myType = amount.GetType();
var myTypeProperties = myType.GetProperties();
foreach (PropertyInfo h_pi in myTypeProperties)
{
if (h_pi.Property_Type == typeof(decimal)) // or h_pi.Name == "Amount" || h_pi.Name == "GrossAmount"...
{
//DoStuff
}
}
}
amount.Amount = GetAmount();
}
there is better way to write that but I'm sure you get the point. Using reflection you could also get rid of the whole interface thing and simply go by reflection.
P.S. : Reflection is not the fastest way to go but it's an easy way to get runtime flexibility.
Let me know if that's what you wanted...
Or, when you do not mind using reflection (it is a bit slower): it is very powerful in combination with attributes. First, create an attribute used to mark the decimal property you need:
[AttributeUsage(AttributeTargets.Property,
Inherited = true, AllowMultiple = false)]
sealed class DecimalFieldAttribute : Attribute
{
public DecimalFieldAttribute()
{ }
}
Mark your field with the attribute, e.g.:
public class SomeGrossAmount
{
[DecimalField]
public decimal GrossAmount
{
get;
set;
}
}
Then use this method to set such a field:
public static void SetDecimalField(object obj, decimal value)
{
// Enumerate through all the properties to find one marked
// with the DecimalFieldAttribute.
PropertyInfo[] properties = obj.GetType().GetProperties();
PropertyInfo decimalfieldproperty = null;
foreach (PropertyInfo property in properties)
{
object[] attributes = property.GetCustomAttributes(typeof(DecimalFieldAttribute), true);
if (attributes.Length == 0)
continue;
// Check, or just break; when you'll not be making this error.
if (decimalfieldproperty != null)
throw new Exception("More than one property is marked with the DecimalFieldAttribute.");
// Found a candidate.
decimalfieldproperty = property;
}
// Check, or just assume that you'll not be making this error.
if (decimalfieldproperty == null)
throw new Exception("No property with the DecimalFieldAttribute found.");
// Set the value.
decimalfieldproperty.SetValue(obj, value, null);
}
I would suggest something like this:
public class Entity
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void Update<TEntity, TValue>(this IEnumerable<TEntity> entities, Func<TValue> valueGetter, Action<TEntity, TValue> valueSetter)
{
foreach (TEntity entity in entities)
{
TValue value = valueGetter.Invoke();
valueSetter.Invoke(entity, value);
}
}
public static decimal GetAmount()
{
throw new NotImplementedException();
}
public static decimal GetOtherAmount()
{
throw new NotImplementedException();
}
public static IEnumerable<Entity> GetEntities()
{
throw new NotImplementedException();
}
static void Main()
{
IEnumerable<Entity> entities = GetEntities();
entities.Update<Entity, decimal>(GetAmount, (entity, value) => entity.Amount = value);
entities.Update<Entity, decimal>(GetOtherAmount, (entity, otherValue) => entity.OtherAmount = otherValue);
}
Just found LinFu - looks very impressive, but I can't quite see how to do what I want to do - which is multiple inheritance by mixin (composition/delegation as I'd say in my VB5/6 days - when I had a tool to generate the tedious repetitive delegation code - it was whilst looking for a C# equivalent that I found LinFu).
FURTHER EDIT: TO clarify what I mean by composition/delegation and mixin.
public class Person : NEOtherBase, IName, IAge
{
public Person()
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
//Name "Mixin" - you'd need this code in any object that wanted to
//use the NameObject to implement IName
private NameObject _nameObj = new NameObject();
public string Name
{
get { return _nameObj.Name; }
set { _nameObj.Name = value; }
}
//--------------------
//Age "Mixin" you'd need this code in any object that wanted to
//use the AgeObject to implement IAge
private AgeObject _ageObj = new AgeObject();
public int Age
{
get { return _ageObj.Age; }
set { _ageObj.Age = value; }
}
//------------------
}
public interface IName
{
string Name { get; set; }
}
public class NameObject : IName
{
public NameObject()
{}
public NameObject(string name)
{
_name = name;
}
private string _name;
public string Name { get { return _name; } set { _name = value; } }
}
public interface IAge
{
int Age { get; set; }
}
public class AgeObject : IAge
{
public AgeObject()
{}
public AgeObject(int age)
{
_age = age;
}
private int _age;
public int Age { get { return _age; } set { _age = value; } }
}
Imagine objects with many more properties, used in many more "subclasses" and you start to see the tedium. A code-gernation tool would actually be just fine...
So, LinFu....
The mixin example below is fine but I'd want to have an actual Person class (as above) - what's the LinFu-esque way of doing that? Or have I missed the whole point?
EDIT: I need to be able to do this with classes that are already subclassed.
DynamicObject dynamic = new DynamicObject();
IPerson person = null;
// This will return false
bool isPerson = dynamic.LooksLike<IPerson>();
// Implement IPerson
dynamic.MixWith(new HasAge(18));
dynamic.MixWith(new Nameable("Me"));
// Now that it’s implemented, this
// will be true
isPerson = dynamic.LooksLike<IPerson>();
if (isPerson)
person = dynamic.CreateDuck<IPerson>();
// This will return “Me”
string name = person.Name;
// This will return ‘18’
int age = person.Age;