Been looking for a way (either built-in, or through a plugin), to automate the properties and defaults when instantiating a class. For example, if I have the following:
public class MyClass
{
string MyPropertyString { get; set; }
int MyPropertyIntWithDefault { get; set; } = 5,
decimal? MyPropertyDecimalWithNoDefault { get; set; }
}
I'd love to be able to say MyClass MyClassImplemented = new MyClass {, hit a button or click an option, and have it automatically finish my code as:
MyClass MyClassImplemented = new MyClass {
MyPropertyString = "",
MyPropertyIntWithDefault = 5,
MyPropertyDecimalWithNoDefault = null
};
I'm guessing I could write an extension or tool myself using reflection, but if anyone has any suggestions that have already been implemented, I'd love to hear them. Thanks!
* EDIT *
To be clear, what I'm looking for is a way to automate the generation of that stub so that I can then change the ones I want to change, instead of having to either type them in manually or copy-paste them from the definition. I know that I can set default values so that I can generate the class with those values automatically.
All that you need is just creating a new instance of your class, then this new instance has all of the properties filled by their default value:
MyClass MyClassImplemented = new MyClass();
You just need to change your class a bit to set the properties a default value (don't forget to use ; after properties, however this works in C#6+):
public class MyClass
{
public string MyPropertyString { get; set; } = "";
public int MyPropertyIntWithDefault { get; set; } = 5;
public decimal? MyPropertyDecimalWithNoDefault { get; set; }
}
Based on your update, it seems what you are looking for, is a way to create a code snippet, so that you would be able to append the properties of the class by hitting some button, in this case you can create a code snippet in Visual Studio, you can go through this tutorial https://learn.microsoft.com/en-us/visualstudio/ide/walkthrough-creating-a-code-snippet?view=vs-2019
Related
Maybe a bit of a philosophical, but should I generally, in C#, expect a property with an interface type to retain its assigned class?
For example a class property like this:
public IBehavior Behavior { get; set; }
that gets assigned a implmented class
instance.Behavior = new ImplementedBehavior();
should i generally expect this cast to succeed?
Assert.IsNotNull(instance.Behavior as ImplementedBehavior);
Or is it lost, and i should have kept a reference to the instantiated ImplementedBehavior instead?
var ib = new ImplementedBehavior();
instance.Behavior = ib;
Assert.IsNotNull(ib as ImplementedBehavior);
Clarification:
Looking to use an external class, that when assigned a class similar to what is done above, changes the content of instance.Behavior internally after i set it, to return an instance of SomeOtherBehavior
Can I assume this is bad behavior and not in the spirit of C#?
GitHub issue related to the question:
https://github.com/aws/aws-cdk/issues/19013
Can I expect a property to retain its assigned class?
No.
It may not even be accepted in the first place, e.g.
public IBehavior Behavior {
get {...}
set { if (!value.HasCapabilityX) return; ... };
}
It may simply be changed by some other code that has access to the same object (instance):
Thread A:
instance.Behavior = new ImplementationA();
Thread B:
instance.Behavior = new ImplementationB();
There are object oriented design patterns that promote the idea of changing the object, e.g. the decorator pattern and proxy pattern, e.g.
public IBehavior Behavior {
get {...}
set { _behavior = new PermissionsDecorator(new LoggingDecorator(value)); };
}
Should I generally expect this cast to succeed?
No.
Or is it lost [...] ?
Maybe.
and I should have kept a reference to the instantiated ImplementedBehavior instead?
If you need something that ImplementedBehavior can do which IBehavior can't do, then yes, keep a reference.
Can I assume this is bad behavior and not in the spirit of C#?
This is not bad behavior. It is good practice to only expect the interface to fulfill the contract that was specified by the interface.
The property can be assigned any value that implements IBehavior:
public class BehaviorA : IBehavior { }
public class BehaviorB : IBehavior { }
...
instance.Behavior = new BehaviorA();
instance.Behavior = new BehaviorB();
So in general, you CANNOT expect a property's value to be of a particular type that derives from the property's declared type.
this
Assert.IsNotNull(instance.Behavior as ImplementedBehavior);
will work so long as you dont change instance.Behavior, it wont happen spontaneously. But if you also have
class Imp2 : IBehavior{
}
and then do
instance.Behavior = new Imp2();
then that assert will fail.
Let me give you a simple example using
public interface IType
{
string Text { get; set; }
int Number { get; set; }
}
public class MyClass
{
public IType MyProperty { get; set; }
}
public class MyFirstType : IType
{
public string Text { get; set; }
public int Number { get; set; }
public char Letter { get; set; }
}
public class MySecondType : IType
{
public string Text { get; set; }
public int Number { get; set; }
public decimal Price { get; set; }
}
And here is the usage with comments that explain what's going on:
var instance = new MyClass(); // creates a new object of type "MyClass" in memory
var myFirstType = new MyFirstType(); // creates a new object of type "MyFirstType" in memory
var mySecondType = new MySecondType(); // creates a new object of type "MySecondType" in memory
// setting property
instance.MyProperty = myFirstType; // MyProperty is now simply referencing "myFirstType" using the address to its position in memory
instance.MyProperty = mySecondType; // The memory address to "myFirstType" is now replaced by the memory address to "mySecondType"
// printing values of MyProperty
Console.WriteLine(instance.MyProperty.Text); // will work.
Console.WriteLine(instance.MyProperty.Number); // will work.
Console.WriteLine(instance.MyProperty.Letter); // compiler error. IType does not specify this "Letter" property.
Console.WriteLine(instance.MyProperty.Price); // compiler error. IType does not specify this "Price" property. However, it is in memory on the object, but the compiler will not infer the type of the property unless the property is explicitly casted.
// casting
var convertedPropertyA = (MyFirstType)instance.MyProperty; // throws an exception since the property is currently set to an object of type "MySecondType".
var convertedPropertyB = (MySecondType)instance.MyProperty; // works because the property is set to an object of type "MySecondType".
// modifying the values of the property
instance.MyProperty.Text = "new text"; // this works
instance.MyProperty.Number = 123; // this works
((MySecondType)instance.MyProperty).Price = 14.99; // this works
Console.WriteLine(instance.MyProperty.Text); // prints "new text"
Console.WriteLine(instance.MyProperty.Number); // prints "123"
Console.WriteLine(((MySecondType)instance.MyProperty).Price); // prints "14.99"
I have a class looking like this:
public class Car
{
public enum Values
{
Brand 1,
Brand 2,
Brand 3
}
public Values _value {get; set;}
}
In my main program I read a text file, that gives certain class names looking like this:
Car(Brand 2)
Dog(Breed 1)
House(Builder 4)
Car(Brand 3)
...
In a first step I create all the entities listed in the text file:
var objType = "Namespace.Car";
var handle = Activator.CreateInstance("AssemblyName", objType);
var childObject = handle.Unwrap();
In the second step I now want to write the value given in the brackets to the property. To do that, I look for the respective property:
PropertyInfo childProperty = childObject.GetType().GetProperty("_value");
Then check, if the property is of type enum:
if (childProperty.PropertyType.BaseType == typeof(Enum))
{
//now set property value
I tried certain things, for example, using SetValue(), but that does not work for enumerations. Is there any way I can do this at runtime?
I looked at the following and people said it would not work, but I think this is not my exact situation: Setting enum value at runtime in C#
Anyone got an idea?
As discussed in the question you mentioned above :
All references to the individual values of an enum are converted to numeric literals at compile time therefore it is not possible to do this at runtime
However you might want to use classes instead of enum, something like this :
public class Car
{
//public enum Values
//{
// Brand 1,
// Brand 2,
// Brand 3
//}
public Brand _myBrand {get;set;}
public Values _value {get; set;}
}
public sealed class Brand
{
public int BrandOne { get; set; }
public int BrandTwo { get; set; }
}
Use Brand class instead of enum, Hope this helps !
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 have a search page which is using strongly typed objects, but I have the values broken into specific groups.
Code behind page calls the following when the user clicks the search button (none of these fields are empty):
SearchCriteria sc = new SearchCriteria();
sc.Generic.id = txtId.Text;
sc.Generic.maxReturned = rblMaxReturned.SelectedIndex;
sc.DisplayOnly.category = txtCategory.Text;
sc.DisplayOnly.type = txtType.Text;
sc.Building.address = txtAddress.Text;
sc.Building.city = txtCity.Text;
The DataType file is defined like this:
[Serializable]
public class SearchCriteria
{
public _Generic Generic { get;set; }
[Serializable]
public class _Generic
{
public int id {get;set;}
public int maxReturned {get;set;}
}
public _DisplayOnly DisplayOnly { get;set; }
[Serializable]
public class _DisplayOnly
{
public int category {get;set;}
public int type {get;set;}
}
public _Building Building { get;set; }
[Serializable]
public class _Building
{
public int address {get;set;}
public int city {get;set;}
}
}
When the code executes, I get a nullreferenceerror even though all the items in the various textboxes have a value. However, if I take out the public _Building Building { get;set; } and call the class directly it works and populates the values. What's the best solution here? Should I not use intermediary definition and call the class directly? If so, how can I call the different groups without making four different calls on the code behind page?
You need to initialize the internal class instances. Simply declaring the variables doesn't mean that you can access their properties without creating the instances. You could easily do that in the constructor of the SearchCriteria class
[Serializable]
public class SearchCriteria
{
public SearchCriteria()
{
// Without these initialization the internal variables are all null
// and so assigning any property of a null object causes the error
Generic = new _Generic();
DisplayOnly = new _DisplayOnly()
Building = new _Building();
}
.....
}
When you create a new instance of your SearchCriteria class, the properties are not initialized, and so they all have a value of null. So now look at the very first line where you try to use one of those properties:
sc.Generic.id = txtId.Text;
Here, txtID.Text is perfectly fine, but sc.Generic is null. When you try to look up the it's .id property for assignment, that's where the exception is thrown.
To fix this, you need to initialize each of those properties to have an instance of their type. Additionally, it's probably a good idea to use a private set, like so:
public _Generic Generic { get;private set; }
This will still allow to make all the same assignments that are currently written, because that only requires a get action to retrieve the type instance. The assignment/set operation is on the property of the property.
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
}