Extension method not setting value - c#

I have a product class that looks something like this -
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
}
I have an extension class that looks like this
public static class ProductExtension
{
public static void FixProduct(this Product product)
{
product = new Product(){Name = product.Name.ToUpper()};
//product.Name is now UPPERCASE
}
}
In my Main method I have -
static void Main(string[] args)
{
Product p = new Product() {ProductId = 1, Name = "steve"};
p.FixProduct();
System.Console.WriteLine(p.Name);
}
This prints "steve" and not what I wanted it to print: "STEVE".
Why doesn't the assignment in the extension method work?

I suggest a small change to follow a fluent interface pattern. Instead of void, return the new product instead. Don't use ref, that is weird.
public static class ProductExtension
{
public static Product FixProduct(this Product input)
{
return new Product
{
Name = input.Name.ToUpper(),
Id = input.Id
}
//product.Name is now UPPERCASE
}
}
Then use it like this:
static void Main(string[] args)
{
var p = new Product()
{
ProductId = 1,
Name = "steve"
}
.FixProduct();
System.Console.WriteLine(p.Name);
}
A neat advantage of this approach is (if you think you will need it) you can support several product classes while preserving their precise type, e.g.:
public static class ProductExtension
{
public static T FixProduct<T>(this T input) where T: Product, new
{
return new T
{
Name = input.Name.ToUpper(),
Id = input.Id
}
}
}
Now you could use it on any derived product class while keeping exactly the same syntax.
class DeluxeProduct : Product
{ }
static void Main()
{
var p = new DeluxeProduct
{
Id = 1,
Name = "Steve"
}
.FixProduct();
Console.WriteLine(p.GetType().Name)); //outputs "DeluxeProduct"
}
Now on the other hand, if all you want to do is "fix" the product's name, you could just wrap it in a property.
class Product
{
private string _name;
public int Id { get; set; }
public string Name
{
get { return _name; }
set { _name = value.ToUpper(); } //Automatically "fix" it the moment you set it
}
}
...and then you don't need an extension method at all.

Extension methods cannot be used that way. In your method you create a new instance of Product and then assign it to product which is a local reference to the passed object, and not the original reference p.
When you first enter the function what you have is two references referencing the same object in memory.
Then just before exiting the method you have two objects, one referred by each reference, with the product reference, referencing a local variable being cleaned by the GC at the end of the method call.
Solutions:
To correct this and have it closest to what you were trying to do,
change your method to get a ref parameter:
public static void FixProduct(ref Product product)
{
product = new Product() { Name = product.Name.ToUpper() };
//product.Name is now UPPERCASE
}
and then:
ProductExtension.FixProduct(ref p);
I believe a better approach all together will be (by having it a
member function or an extension method) to update the object instead
of instantiating a new one:
public static void FixProduct(this Product product)
{
product.Name = product.Name.ToUpper();
}

In your extension method, you are assigning a new Product to the variable product. This doesn't end up affecting the original referenced Product.
Modify the method to the one below to set the name on the original passed in object.
public static void FixProduct(this Product product)
{
product.Name = product.Name.ToUpper();
}

Parameters are passed by value unless they are ref or out. this doesn't change that. You can understand this syntactically because ref and out require a variable reference; otherwise only an expression is required.
Unfortunately, you can't combine this with ref or out.
You can change the value of any parameter variable, though, except in the case of ref or out, it's best avoided or limited to quick touch-ups to the passed-in value that simplify later algorithmic code.
A method is permitted to assign new values to a value parameter. Such
assignments only affect the local storage location represented by the
value parameter—they have no effect on the actual argument given in
the method invocation.
— C# Language Specification
So, the assignment does work, just not in the ref or out way.

Related

Anonymous type with var gives error CS0825 [duplicate]

This question already has answers here:
Implicit typing; why just local variables?
(6 answers)
Closed 1 year ago.
I want to create an anonymous type in C# inside a class.
The examples I have seen use var to create an anonymous variable
var RecordId = new
{
Foo = 0,
Bar = "can be also a string"
};
However I want to create my anonymous variable inside a class.
public class Logger //: LogBase
{
var RecordId = new
{
Foo = 0,
Bar = 1
};
}
So when Logging I can do:
Logger.RecordId.Foo
But declaring my anonymous type as var triggers the following error:
CS0825: The contextual keyword 'var' may only appear within a local variable declaration.
What is the type of an anonymous variable, so I don't have to use var?
I understand what the error is telling me, but I don't want to move my variable inside a function, it needs to be a property of Logger.
Edit: enum is what I tried t the beginning, but I need the values to be more flexible than just integers (like strings, so I can dump jon files).
I updated my question to reflect that.
var (and by definition anonymous types) can only be declared inside a method, the error message is basically telling you that. If you need this type to be at class level, then make a class/struct/tuple to store it.
public static class Record
{
public static int Foo { get; set; }
public static int Bar { get; set; }
}
public class Logger //: LogBase
{
public static Record RecordId { get; set; } = new Record();
}
Now you can do this:
var foo = Logger.RecordId.Foo;
Note that I also used static so you don't need to create a new instance of the class, but change that if you think it's relevant.
public class Logger //: LogBase
{
public enum RecordId
{
Foo = 0,
Bar = 1
}
}
If you do not want strings you can do the above.
public class LogCategory
{
private LogCategory(string value) { Value = value; }
public string Value { get; private set; }
public static LogCategory Foo { get { return new LogCategory("Foo"); } }
public static LogCategory Bar { get { return new LogCategory("Bar"); } }
}
If you want strings you could create your own class something like the above.
You can use the dynamic type to have an anonymous instance variable.
public class Foo
{
dynamic bar = new {
A = 1,
B = 2
};
public void Print() {
Console.WriteLine(bar.A);
}
}
Try it out!
Just because you can do this doesn't mean it's a good idea. See DavidG's answer for an alternative using a strongly-typed object that will not require you to expose your code to the many problems associated with the dynamic type.

How to implement the default constructor (using constructor chaining) that sets the Category to Miscellaneous

I am very new to programming so I was trying to do some work with and got stuck with my problem.
Here is my code:
//Properties
private static readonly List<string> category = new List<string>
{
"Electric",
"Household",
"Garden",
"Miscellaneous"
};
Category HAS to be "readonly"
// Constructor
public Product(List<string> category)
{
// this.category shows error that it cannot be accessed with an instance reference;
// qualify it with a type name instead
this.category = category;
}
Also in the default constructor I cannot pass it
// Default Constructor
public Product() : this("Miscellaneous")
{
}
So, how to pass 1 one of strings within the list? Or should I use arrays for this? And how do I print it out later?
class TestProduct
{
static void Main(string[] args)
{
// Assigning correct properties to the product
Product p1 = new Product(1234567, "Cake", "Miscellaneous", 7.5, 150);
Console.WriteLine(p1);
Console.ReadLine();
}
}
Hope my question is clear.
If you have a fixed set of categories, you can use an enum to store all values.
public enum ProductCategory
{
Electric,
Household,
Garden,
Miscellaneous
}
You can create a default constructor like this:
public enum ProductCategory
{
Electric,
Household,
Garden,
Miscellaneous
}
public class Product
{
public ProductCategory Category { get; }
public Product(ProductCategory category)
{
this.Category = category;
}
public Product() : this(ProductCategory.Miscellaneous)
{
}
}
static void Main()
{
Product p1 = new Product();
Console.WriteLine(p1.Category); // output: Miscellaneous
Console.ReadKey();
}
If you still want to store your category in a string, you can adapt this example. If you want a fixed list of valid categories, you can check if the category is valid in the constructor.
Category HAS to be "readonly"
The problem is not that it is readonly, the reason why you're getting cannot be accessed with an instance reference, qualify it with a type name instead is because you declared the property as static. A static property cannot be accessed as an instance property.
Also in the default constructor I cannot pass it
Yes you can, if you actually pass in the type you declared.
public Product() : this("Miscellaneous") //You're trying to pass in a string
{
}
Can you see why you cannot pass in that string into your base constructor?
public Product(List<string> category) //base constructor takes a List<string>
{
//stuff
}
You could create a base constructor which actually takes a string:
public Product(string cat)
{
//Validate that the category passed in is valid, I.E. in your list
foreach (var item in category)
{
if(object.Equals(item, cat))
break;
if(object.Equals(item, category.Last()))
throw new Exception("D'oh! Invalid category");
}
//do stuff
}
Something like that. There are probably better ways to validate. Or just make your categories an Enum and use something like Enum.TryParse to validate instead.
I assumed you don't actually want it to be a static variable (this question might help), as long as you are receiving it in the constructor. Maybe what you want it is to be immutable, which is something quite different.
You can define that constructor this way.
public class Product
{
private readonly List<string> _categories;
public Product() : this(new List<string>() { "Miscellanous"})
{
}
public Product(List<string> category)
{
_categories = category;
}
}
Or this way
public class Product
{
// other code
public Product()
{
categories = new List<string>();
categories.Add("Miscellanous");
}
}
Also readonly only forbids changing the reference to the _categories variable. If you want the content to be immutable, then you should have a look at other kind of data structures or simply do it in the code.
Remove the this qualifier from this.category because you are accessing a static variable which by definition cannot belong to an instance of a class.
Of course this means you'll get a naming collision because the static category cannot be differentiated from the local category - so fall back to using a naming convention like an underscore at the start of the name for the static variable - _category.
You should also rethink why you made the private variable category static - there is no reason for it to be that way.
[...] that sets the Category to Miscellaneous
To solve your main issue - there is no way to do this without writing a new constructor that takes a single string (because you cannot statically define or enforce the length of a List<>, you can only check that programmatically). A good option is to use enums as suggested by #apk, then throw an ArgumentOutOfRangeException from within the chained constructor if the value Miscellaneous isn't passed in. But you should rethink even that strategy - if the value must be Miscellaneous then consider defaulting to that in the chained constructor, don't allow an arbitrary value to be passed in and then test for the one possible correct value.

.Net arbitratry runtime class instantion and method calling

I am looking for a way to do arbitrary class instantion as well as attribute assignement and possibly method calling in .Net and preferrably C#. Since arbitrary is too broad a word let me tell you what I am after.
Let's say I have a DLL (objects.dll) that contains:
public class Person
{
// Field
public string name;
// Constructor that takes no arguments.
public Person()
{
name = "unknown";
}
// Constructor that takes one argument.
public Person(string nm)
{
name = nm;
}
// Method
public void SetName(string newName)
{
name = newName;
}
}
public class Table
{
// Field
public int width;
public int lenth;
public int height;
// Constructor that takes no arguments.
public Table()
{
width = 0;
length = 0;
height = 0
}
// Constructor that takes three arguments.
public Table(int w, int l, int h)
{
width = w;
length = l;
height = h;
}
// Method
public void SetWLH(int w, int l, int h)
{
width = w;
length = l;
height = h;
}
}
public class Printer
{
public Printer(){}
public void printAPerson(Person p)
{
//do stuff with p
}
public void printATable(Table t)
{
// do stuff with t
}
}
I want to be able to instantiate either of the classes above, set attribute values and call methods at runtime from a different program in the most generic possible. eg. lets say I hame a programm called myprog.exe, i want to be able to do the following
myprog.exe objects.dll Person name testname Printer printAPerson
where:
objects.dll is the dll that contains all required classes
Person is the first I will instantiate name is its attribute
testname is the value I will assign to this attribute
Printer is the class I will use for printing
printAPerson is the method in the Printer class I need to call with the specified object as a parameter.
As you can see, in the best case for my use scenario, neither of the objects and classes are/will be known at compile time so I would like to be as non-casting as possible. If that is not possible I will take what I can.
I have seen this, How to use reflection to call a method and pass parameters whose types are unknown at compile time?, which to my limited knowledge kind of does what I want minus the casting bits or I could be mistaken.
Thanks a lot!
Instead of using Reflection you could use dynamic. But this requires that the Printer class and others are changed. And you would loose intellisense and compile time checks.
public class Printer
{
public Printer() { }
public void printAPerson(dynamic p)
{
//do stuff with p
Console.WriteLine("Person name: " + p.name);
}
public void printATable(dynamic t)
{
// do stuff with t
Console.WriteLine("printATable(Table p) is called");
}
}
public class TestDynamic
{
public static void Test()
{
// To get the type by name,
// the full type name (namespace + type name) is needed
Type personType = Type.GetType("StackOverflowCodes.Person");
object personObj = Activator.CreateInstance(personType);
// Implicit cast to dynamic
dynamic person = personObj;
person.SetName("Alan Turing");
Type printerType = Type.GetType("StackOverflowCodes.Printer");
object printerObj = Activator.CreateInstance(printerType);
dynamic printer = printerObj;
printer.printAPerson(personObj);
}
}
Are you flexible concerning your executable input format? If so, you could do what you want by having a convention. I would do this using a JSON structure like this one:
{
Command : "",
Arguments : {
Argument1 : 0,
Argument2 : { }, // can be another complex object
Argument3 : [] // an empty array maybe ...
}
}
Where Command would be something like "ClassName.MethodName", Arguments will be a JSON object that each object property represents your method parameter.
In your executable, you must parse this JSON using a library (example http://www.newtonsoft.com/json) and use reflection to deserialize every JSON object parameter and call your method. If you cannot get it work, please let me know I will try to make an example (if I will have time, this night because I am at work right now).
For your case you just want to print an object of type Person to the printer right? You could execute a command like this:
{
Command : "Printer.PrintAPerson",
Arguments : {
p : { name : 'george' }
}
}
If you want to rely on a standard protocol, please check the JSON-RPC protocol: http://json-rpc.org/wiki/specification

How to get filled interface instance as a parameter of a method after executing the method?

I have a method that fills an instance of an interface as bellow:
private static void Caller() {
IOrder order = null;
MakeOrder(order);
//order is empty
}
private static void MakeOrder(IOrder order) {
order = new Order
{
PeriodCount = mciOrderInfo.PeriodCount,
Quantity = mciOrderInfo.Quantity,
ShoppingItemId = shoppingItem
};
}
After executing this method MakeOrder the Caller will get order = null but this method fills order as above.
I know if the type of parameter was a class Order instead of interface IOrder, it will be filled and accessible in Caller method.
What is the problem?
The simpelst way is to use return:
private static void Caller()
{
IOrder order = MakeOrder();
}
private static IOrder MakeOrder()
{
return new Order
{
PeriodCount = mciOrderInfo.PeriodCount,
Quantity = mciOrderInfo.Quantity,
ShoppingItemId = shoppingItem
};
}
Or, if for some reason you want to do otherwise, you can use ref/out:
private static void Caller()
{
IOrder order;
MakeOrder(out order);
}
private static void MakeOrder(out IOrder order)
{
order = new Order
{
PeriodCount = mciOrderInfo.PeriodCount,
Quantity = mciOrderInfo.Quantity,
ShoppingItemId = shoppingItem
};
}
ref passes the parameter by reference, which means if you modify it inside your function the caller's variable will be modified.
out is basically the same, except the caller doesn't have to initialize the variable, it's always the responsibility of the callee.
Yet another way would be to pass an instance and fill its properties:
private static void Caller()
{
IOrder order = new Order();
MakeOrder(order);
}
private static void MakeOrder(IOrder order)
{
order.PeriodCount = mciOrderInfo.PeriodCount;
order.Quantity = mciOrderInfo.Quantity;
order.ShoppingItemId = shoppingItem;
}
This works because classes (and interfaces for that matter) are reference types.
You should read this MSDN article: Passing Reference-Type Parameters.
The problem is that you're dealing with multiple variables here.
This line:
MakeOrder(order);
calls MakeOrder with a copy of the value of that variable, which currently is null. Inside MakeOrder you change the local parameter variable to a new value, but the original order variable on the outside is still null.
Perhaps you want to use a return type instead:
private static void Caller()
{
IOrder order = MakeOrder(order);
}
private static IOrder MakeOrder()
{
return new Order
{
PeriodCount = mciOrderInfo.PeriodCount,
Quantity = mciOrderInfo.Quantity,
ShoppingItemId = shoppingItem
};
}
Also note that the type of the parameter has nothing to with this, even if you changed MakeOrder to take a parameter of type Order (a class) you would still have the same problem.

How do I get the value of the used parameters in a constructor (C#)

I've got a question about getting the values from a constructor in a generic way.
namespace myTestNamespace
{
Public Class myTestClass()
{
Public myTestClass(int myInt,bool myBool, double myDouble)
{
//do / set something
}
Public myTestClass(int myInt,bool myBool)
{
//do / set something
}
}
}
Using (what you need);
Using myTestNamespace;
namespace MyIWannaLookForTheParametersName
{
Public Class MyLookUpClass()
{
Public void DoSomething()
{
List<object> myList = new List<object>();
myTestClass _ myTestClass = new myTestClass(1,true,2.5);
object mySaveObject = myTestClass;
mylist.Add(mySaveObject);
//how do I get the info from the right constructor
//(I used the one with 3 parameters_
//what was the value of myInt, myBool and myDouble
//how can I make it generic enough, so it will work with other classes with
// different constructors ass well?
}
}
}
Questions about intent aside, there's no generic way for you to do this. Information about what methods have been called and what values were supplied is not saved automatically. You are, of course, perfectly able to keep track of these things yourself, but you would have to write each class to do this explicitly.
Doing this in a generic way is asking for trouble. What if I did this?
public class Foo
{
public string Name { get; set; }
}
public class Bar
{
public Bar(Foo foo)
{
// ...
}
}
Then suppose I called it in this way:
Foo f = new Foo();
f.Name = "Jim";
Bar b = new Bar(f);
f.Name = "Bob";
Now, if such a generic system existed, what would be the value of foo for the Bar constructor? Either it reports "Bob" (which is what the value for Name is on the instance of Foo that was supplied), or it reports "Jim", meaning that the runtime or library would essentially have to be smart enough to make a deep copy of the object so that the state is not changed.
The bottom line is this: if you need access to the parameters passed to the constructor (or any other function), you'll have to store them somewhere explicitly.
You can't get thevalues from the constructor. You need to first place them in a property or a field within your class. The example you provided is a poor use of generics. You wouldbe better off placing the constructor values into properties and creating an interface with those properties.
I got what I needed with this method:
private static ParameterSettings[] GetListOfParametersFromIndicator(object indicatorClass, int loopId, myEnums.ParaOrResult paraOrResult)
{
return (from prop in indicatorClass.GetType().GetProperties()
let loopID = loopId
let Indicator = indicatorClass.GetType().Name
let value = (object)prop.GetValue(indicatorClass, null)
where prop.Name.Contains("_Constr_")
select new ParameterSettings { ParaOrResult=paraOrResult, LoopID= loopId, Indicator= Indicator, ParaName= prop.Name, Value= value }).ToArray();
}
where ParameterSettings is:
public struct ParameterSettings
{
public myEnums.ParaOrResult ParaOrResult { get; set; }
public int LoopID { get; set; }
public string Indicator { get; set; }
public string ParaName { get; set; }
public object Value { get; set; }
}
This info is ok for me. Thanks for the replies.
Regards,
Matthijs

Categories

Resources