I know that in a widening conversion, the destination data type can hold any value provided by the source data type. I can understand this when convert value type,
but can't between reference types. My question arises from follows scenario:
public class Person
{
public string Name { get; set; }
}
public class Employee : Person
{
public string SurName { get; set; }
}
static void Main(string[] args)
{
Employee emp = new Employee { Name = "Elvin", SurName = "Mammadov" };
Person prs = emp;
}
As shown, the Person class is ancestor class of Empoyee. In previouse code, I create reference of Emplyee class, and then convert Employee object into a Person. At this point, I lose SurName data field and value.
I want to know:
Is it countary to can hold any value expression?
Why conversion a reference type to a direct or indirect ancestor class or interface is a widening conversion?
thanks for reply
It would be called a 'widening conversion' because you're becoming less specific with regard to the references type, you're widening the set of potential types. When you have an Employee reference you know that you can use any functionality specific to that class, when you have a Person reference to the same object you only know that you can use functionality contained in the Person class. If you want to use Employee specific functionality with your prs reference you'll first have to cast your reference back to an Employee reference and if prs isn't actually of type Employee (perhaps it's of type Customer which also inherits from Person) then you will get an InvalidCastException.
The SurName property does not go away when you're dealing with a Person reference. You just cannot access it because it is not contained within the Person class. Basically, if you have a reference of the base classes type, you will only be able to access properties/methods contained within the base class. It doesn't matter that it is actually an Employee, you have a Person reference, so the object is treated accordingly.
The conversion is not useful in your example. The conversion is useful when you're attempting to work with many child classes in a generic manner. As an example, I may have a Person class. In addition to that I have Employee, Customer, and Consultant classes which inherit from it. Now lets suppose I have a Store object and I want to do something like get the names of every Person who is currently in the store. The simplest way to solve this problem would be to have a List<Person> with all the people in the store. Because Employee, Customer, and Consultant all inherit from Person I could do
peopleInMyStore.Add(MyEmployee);
peopleInMyStore.Add(MyCustomer);
peopleInMyStore.Add(MyConsultant);
Then later on I can do something like;
foreach (Person p in peopleInMyStore)
{
Console.WriteLine(p.Name);
}
This concept is referred to as 'polymorphism' and can be read about here http://en.wikipedia.org/wiki/Polymorphism_(computer_science)
My example is contrived, but this is one of the main reasons you use inheritance. To give you a real example I have some test code where I have a class called ApiTestSuite then I have about a dozen classes that all inherit from it of the form SpecificApiTestSuite. The project builds into a command line executable, you invoke it with an api parameter (api=specificApiName) then I can do something like;
ApiTestSuite tests;
if (args[0] == "api1")
tests = new Api1TestSuite();
else
tests = new Api2TestSuite();
tests.RunTests();
Related
Below is a Person class. Currently, it can only be used to instantiate a single Person object. I would like to change it so it can accept a list of full names and result in a collection of Person objects.
using System;
namespace Test
{
public class Person
{
public string FullName;
public string Organization;
public Person(string Organization, string FullName)
{
this.FullName = FullName;
this.Organization = Organization;
}
}
}
This would ideally be similar to the Fileinfo class. This class can be initialized by either providing a single file name or a list of file names. I would also like to be able to initialize this Person class to be constructed using either a list of full names or a single name.
I don't think the FileInfo class works the way you're expecting—but I now understand what you're asking. As mentioned in the comments, you're going to need two classes. The first one is for your business object—in this case Person. The second one will be a collection-based class, such as PersonCollection.
As an alternative, you can alter your data model so that you have a separate Organization and Person class. In that model, your Person class would have a FullName property, but not an Organization property. I'll address that option at the end.
Instead of just offering code, I'll attempted to explain the concepts as I go, while also flagging issues you're likely going to run into along the way. That makes for a longer post. But given the nature of the question, I hope this additional detail will prove valuable.
Business Object
Your Person class can continue to operate exactly the way you've proposed. That said, there are a couple of improvements you might consider.
First, if your business object is never going to be modified after you've instantiated it—i.e., it's immutable—then you can use the C# 9.0 record syntax, which allows your constructor to define properties directly:
public record Person(string Organization, string FullName);
Alternatively, if you prefer to keep this as a class, then I'd recommend implementing it as follows:
public class Person
{
public string Organization { get; set; }
public string FullName { get; set; }
public Person(string organization, string fullName)
{
Organization = organization;
FullName = fullName;
}
}
Notes
I've used the auto-implemented property syntax for Organization and FullName; otherwise, they will be treated as public fields, which have slightly different semantics (source).
I've updated your parameter names to be camelCase, so you don't need to assign property values with the this prefix. This is standard in C#.
I think it's more intuitive for the fullName to be your first parameter, but that's a stylistic preference, so I've kept this consistent with your original code.
Collection-Based Class
There are a number of ways to create a strongly typed collection-based class. The easiest is to simply inherit from Collection<Person>:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people)
{
Add(person);
}
}
}
Notes
You could also call this People, as I did in the comments, but Microsoft recommends that strongly typed collection classes start with the item type (i.e., Person) and end with Collection (source).
You could also derive from e.g., List<Person>, but Microsoft recommends using the more familiar Collection<> class (source).
The params keyword allows you to accept an array—in this case of Person objects—but pass them as a list of parameters, instead of an array (details). This makes for a friendlier and more intuitive interface in this case.
You could instead accept an array of strings—e.g., fullNames—in order to construct a new Person object for each one, as you requested. But as your current Person object also needs an Organization parameter, it's easier to first construct the Person object, and then pass it to the collection.
Usage
You can now construct the class by creating some Person instances and passing them to the PersonCollection constructor as follows:
//Construct some Person objects
var robert = new Person("Robert, Inc.", "Robert");
var jeremy = new Person("Ignia, LLC", "Jeremy")
//Construct a new PersonCollection
var people = new PersonCollection(robert, jeremy);
Alternatively, if you're using C# 9.0 (e.g., with .NET 5+), and are hard-coding your Person initializers, you can also use the following syntactical shorthand:
var people = new PersonCollection(
new ("Robert, Inc.", "Robert"),
new ("Ignia, LLC", "Jeremy")
);
This looks similar to your request to pass in a list of full names—except that it accounts for your Organization property, and results in a full Person object for each. If you'd truly prefer to just pass in an array of names, see Organization-Based Model at the end of this answer.
Validation
In practice, you probably want to add in some validation to ensure that each Person reference is not null, and that at least one Person instance is passed to your constructor. If so, you can extend this to include some validation. Here's one possible approach to that:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people?? Array.Empty<Person>())
{
if (person is null)
{
continue;
}
Add(person);
}
if (Count == 0)
{
throw new ArgumentNullException(nameof(people));
}
}
}
I default to the Array.Empty<Person> on the loop so that we don't need to do two checks—first for the people length, and then for the PersonCollection length. But you can adjust to your preferences.
Organization-Based Model
In the comments, you proposed an alternate constructor:
public People(string Organization, string[] FullName) { … }
This implies a different data model. If you're going to have one organization that can have multiple Persons associated with it, I'd instead create an Organization business object:
public record Person(FullName);
public class Organization
{
public readonly string Name { get; }
public readonly Collection<Person> Members { get; }
public Organization(string name; params string[] members)
{
Name = name?? throw new ArgumentNullException(nameof(name));
foreach (var memberName in members)
{
Members.Add(new Person(memberName));
}
}
}
Notes
In this model, each Organization has a Name and then multiple Members—each represented by a Person object.
Because the organization name is handled at the Organization level, it is presumably not needed on each Person object.
The Members collection could be replaced with a Collection<string> if you just need a list of names. But maintaining a Person object offers more flexibility.
You can obviously incorporate the previously proposed validation logic into this constructor as well.
You could also add an overload of the constructor that accepts a Person[] array to offer more flexibility.
I have a class:
public class Person {
public string FirstName = "";
public string LastName = "";
}
and a derived class:
public class HRPerson : Person {
public string GetSomething() {
//calculate something
}
}
Essentilly, I'm wanting to extend the functionality of the base class. The use looks like this, where GetAllPerson returns List<Person>.
class Program
{
static List<HRPerson> GetAllHRPerson()
{
List<HRPerson> HRPersonList = new List<HRPerson>();
foreach (Person person in GetAllPerson)
{
HRPersonList.Add(person);
}
return HRPersonList;
}
}
It doesn't compile, saying that there is no overload for the parameter, and when I try to cast person to HRPerson, I get the runtime error "unable to cast object of type Person to type HRPerson" error.
How do I go about adding additional functionality like this?
It sounds like your GetAllPerson is returning some non-HR people...
Assuming that's the case and you just want to filter those out, it's easiest to use LINQ's OfType method:
static List<HRPerson> GetAllHRPerson()
{
return GetAllPerson().OfType<HRPerson>().ToList();
}
(Side note: please avoid public fields like this, other than for constants. Fields should be an implementation detail, not part of your public API.)
Of course if none of your Person instances are actually instances of HRPerson, that's not going to help you. You can't change the type of an instance once it's been created. It's not really clear what your situation is - if this answer doesn't help you, please provide more details.
EDIT: I'm still not really sure that you want an extension method, but if you do, it would be something like:
public static class PersonExtensions
{
public static string GetSomething(this Person person)
{
// Do something with the given Person
}
}
You can then call that on any Person as if it were an instance method:
Person person = ...;
string something = person.GetSomething();
But this is not polymorphic - it's not that you're changing anything about the Person object, which your description still makes it sound like you really want to do...
Based on your comments to Jon Skeet's answer, is this what you are looking for:
Create a subclass of Person, for example, NamedPerson. Give NamedPerson a method GetFullName, which returns the full name of the Person.
Then create a subclass HRPerson from NamedPerson, and override GetFullName to return the name in a slightly different format. CCPerson would also be subclassed from NamedPerson.
You have no control over Person, but you have full control over NamedPerson. Then what you want is a list of NamedPersons, not of HRPersons. This list could contain bare NamedPersons, or HRPersons, or CCPersons, but all objects on the list would be NamedPersons or subclasses of it, so they would all have GetFullName.
What is the best way of the following 2 suggestions to modify a property on an object that is being modified by a class that accepts the object as a parameter?
Have the class work on the object and a return a value which you then assign to the object
or.
Pass the object in using the ref keyword and have the class amend the object without actually returning anything.
For example, I have a Person object with a First Name and Last Name and 2 different ways to create the Full Name.
Which is the best way?
public static void Main()
{
Person a = new Person { FirstName = "John", LastName = "Smith" };
Person b = new Person { FirstName = "John", LastName = "Smith" };
NameProcesser np = new NameProcesser();
// Example A
a.FullName = np.CreateFullNameA(a);
// Example B
np.CreateFullNameB(ref b);
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get; set; }
}
public class NameProcesser
{
public string CreateFullNameA(Person person)
{
return person.FirstName + " " + person.LastName;
}
public void CreateFullNameB(ref Person person)
{
person.FullName = person.FirstName + " " + person.LastName;
}
}
You don't need ref. Just modify the object in your method.
When an reference type is passed as a parameter, it is passed "by reference", not by value. So when you modify it, you're actually modifying the original object. You only need ref if you are passing a value type such as an int.
I say "by reference" in quotes, because what is actually happening is that an internal "pointer" to the original object is being passed by value.
First things first
The fact that you're mentioning ref suggests that you are missing a fundamental notion; that is, code that can access a reference to an object can by definition have access to the actual object.
The only conceivable usage scenario in which you would use a ref parameter is when you want to set that reference to some other object, or to null.
If you don't use ref (or even out for that matter, see the difference here) you are actually passing your argument by value, which means that a copy of it is created.
This means two things, depending on whether the parameter is a value type (like int, long, float etc) or a reference type (reference to an instance of whatever class).
If a parameter is a value type, a copy of it will be created. Your method can then do whatever it wants to it, because the copy is only limited to that method's scope.
If a parameter is a reference type, however (as your Person would be), only the reference itself gets copied: the underlying object is the same. This is where the big difference lies. Keep in mind, however, that the reference you have available inside the method is still a copy of the original one, which means that you can set it to null, set it to another object and, in short, do whatever you like with it: once the method has returned, that reference will disappear, and the original one will be left untouched.
That being said
As others told you, there's really no need to use ref.
Moreover, as long as you're dealing with trivial cases such as concatenating first and last name, I would let the object itself do it (exactly like Slapout did).
There's always time to separate responsibilities later should such a need arise.
Consider also that having a separate class for such a trivial task might be also considered counterintuitive.
Say this is the code at hand:
var p = new Person() { FirstName = "John", LastName = "Smith"} ;
Console.WriteLine(p.FullName);
When I do that, I fully expect FullName to return something meaningful (i.e. "John Smith") at all times.
With both your approaches, instead, what will happen if I forget (and I will) to call CreateFullName?
Should you really need to move a given concern into a separate class, hide it inside the property's get method.
That way, people won't need to know about the underpinnings of the classes you wrote, and it's still testable.
Neither - and you don't need 'ref' - just use:
public void CreateFullNameB(Person person)
{
person.FullName = person.FirstName + " " + person.LastName;
}
At first, the only reason to separate the method into a other class is if that method have dependencies like database or network access. Otherwise that simple method should be a property of Person class.
Also it is only reason to pass whole object to method is when object data is widely used inside that method. Otherwise it is better to pass FirstName and LastName as parameters and return result.
Classes don't need to be passed with ref modifier to modify their content. ref is only required if method want assign parameter with a reference to a new instance.
In example you described if choose from two options the return value is better because it makes less coupling and separates logic from data representation. But if few properties of an entity can be updated, then passing object is better.
I have a entity class that it name is Person. The Person entity has a list of Asset entity.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Asset> Assets { get; set;}
}
For example I have two Person (person1 & person2). I need to copy list of assets from person1 to person2. I do it like following code :
Person person1 = LoadById(1);
Person person2 = LoadById(2);
// person2.Assets = person1.Assets; // Is it correct?
foreach(Asset item in person1.Assets)
{
//person2.Assets.Add(item);
Asset asset = new Asset();
asset.Title = item.Title;
asset.Description = item.Description;
asset.Person = person2;
person2.Add(asset);
}
person2.Update();
There is a better way to do this?
The Assets property is a reference to a list. person2.Assets = person1.Assets; would mean they both share and point to the same list, so would not be separate.
You want to do :
person2.Assets = new List<Asset>(person1.Assets);
(Just going to check that overload, but that should copy all the contents)... Yes, that should do it.
If you wanted to add them rather than replace, use this:
person2.Assets.AddRange(person1.Assets);
You might get duplicates, however. You could do this if you don't want that: Linq to entities : Unions + Distinct
Also, you have an additional () - your first line should just be, public class Person.
As a starting point I recommend this MSDN documentation of the MemberwiseClose method.
This would make your copying process a lot more readable. But note that this also just creates a shallow copy of your list.
If you really need a deep copy, the article suggests this strategies:
There are numerous ways to implement a deep copy operation if the
shallow copy operation performed by the MemberwiseClone method does
not meet your needs. These include the following:
Call a class constructor of the object to be copied to create a second object with property values taken from the first object. This
assumes that the values of an object are entirely defined by its class
constructor.
Call the MemberwiseClone method to create a shallow copy of an object, and then assign new objects whose values are the same as the
original object to any properties or fields whose values are reference
types. The DeepCopy method in the example illustrates this approach.
Serialize the object to be deep copied, and then restore the serialized data to a different object variable.
Use reflection with recursion to perform the deep copy operation.
I have number of DTO classes in a system. They are organized in an inheritance hierarchy.
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string ListName { get; set; }
}
class PersonDetailed : Person
{
public string WorkPhone { get; set; }
public string HomePhone { get; set; }
public byte[] Image { get; set; }
}
The reason for splitting it up is to be able to get a list of people for e.g. search results, without having to drag the heavy image and phone numbers along. Then the full PersonDetail DTO is loaded when the details for one person is selected.
The problem I have run into is comparing these when writing unit tests. Assume I have
Person p1 = myService.GetAPerson();
PersonDetailed p2 = myService.GetAPersonDetailed();
// How do I compare the base class part of p2 to p1?
Assert.AreEqual(p1, p2);
The Assert above will fail, as p1 and p2 are different classes. Is it possible to somehow only compare the base class part of p2 to p1? Should I implement IEquatable<> on Person? Other suggestions?
I believe that Assert.AreEqual calls the Equals method on the instances involved. You should be able to simply override the Equals logic and check to see at runtime whether you are comparing one of the possible cases:
Person <-> Person
Person <-> PersonDetailed
PersonDetailed <-> Person or
PersonDetailed <-> PersonDetailed
You can them implement the appropriate logic for each case, or delegate to an external comparer as you see fit. I don't know off-hand if any unit testing frameworks other than Microsofts support checking for IEquatable<T> when you ask them to verify equality.
A bit more investigation (based on LBushkin's answer) made me change my mind.
Assert.Equals calls the Equals method to compare the object. In my case I could have created an override on Person that would accept any type that can be casted to a Person and then compares all the attributes. This would make my original code work:
Assert.AreEqual(p1, p2);
I would also have to override Equals in my PersonExtended class to check the extra fields present. However that would have "funny" consequences:
Assert.AreEqual(p1, p2); // calls p1.Equals(p2) - evaluates to true.
Assert.AreEqual(p2, p1); // calls p2.Equals(p1) - evaluates to false.
At this point I decided to build something more simple - the result was an extension method on the Person type that compares. This has some advantages:
Can handle a null left-hand argument.
It is non-virtual - it is clear that the declared type of the variable is the comparison
used.
Now all appeared to be well and I could continue coding. Until I found out that the entire idea of having inheritance between the basic and extended DTOs is flawed. I thought that the DataContractSerializer that WCF uses would serialize the type that the parameter of the function was declared as. It doesn't. It serializes the object's actual type. That means that if a PersonExtended object is passed to a method that only requires a Person the entire extended method is transferred over the wire anyways, so it's better to stick with simple composition.