This question already has answers here:
IEnumerable vs IReadonlyCollection vs ReadonlyCollection for exposing a list member
(5 answers)
Closed 3 years ago.
Let's have this class:
ExampleClass
{
public List<string> MyValue { get; set; }
}
The question is how to restrict outside classes to modify of that property, means add object to collection, make new().
you can have something like this
public ReadOnlyCollection<string> MyValue {get; private set;}
You could expose it as IEnumerable<string> instead of as a list. This interface will not allow adds. You can still store it as a list internally, as a private field, so that the class itself can add or remove if needed.
For example:
class ExampleClass
{
private List<string> _myValue = new List<string>();
public IEnumerable<string> MyValue
{
get
{
foreach (var s in _myValue) yield return s;
}
}
}
If the caller would like to work with its own list, it can of course do this:
var list = exampleClass.MyValue.ToList();
At which point the caller owns it and it is clear that anything it chooses to add has nothing to do with the original list.
Related
This question already has answers here:
convert a list of objects from one type to another using lambda expression
(14 answers)
Closed 1 year ago.
I'm struggling with this a little.
I have a List<HeadStruc_Table> within my program.
The Class HeadStruct looks like following:
public partial class HeadStruct_Table : IComparable<HeadStruct_Table>
{
public string colName { get; set; }
public string colName_edit { get; set; }
public string alternativeNames { get; set; }
public int Table_ID { get; set; }
public bool colFound { get; set; }
public CheckBox cBox { get; set; }
I don't know how to create a method with parameters (List<HeadStruct_Table>, HeadStruct_Table.colName) that then returns a List<TypeOf(HeadStruct_Table.colName)> containing only the values of colName in this specific case.
Of course it should work for the bool and even CheckBox property as well.
As parameter HeadStruct_Table.colName doesn't work right now, as it is declared as just public and not public static, do i have to declare it as public static or is there any other chance to pass the specific property. Maybe by using a predicate?
That's the way it maybe could look like later?
public static IList<T> getList<T>(List<HeadStruct_Table> list, Func<HeadStruct_Table, T> getType)
{
var newList = new List<T>();
I just don't know how to get the special property and then, in the method, just read out those values. I wouldn't like to work with a string as parameter if it works without.
Anyone who has an idea?
That is my first question. I'm open for any advice to improve asking a question in here. Thank You.
LINQ's Enumerable.Select method already does what you want:
var newList = list.Select(x => x.colName).ToList();
This question already has answers here:
What is difference between Init-Only and ReadOnly in C# 9?
(4 answers)
Closed 1 year ago.
I can define a class like below:
public class MyClass
{
public int Id { get; }
public MyClass(int id) => Id = id;
}
And I have to define the Id from the constructor and it will be read-only.
But if I want to use Init only setters in the C# 9.0, what does it and how can I use it?
public class MyClass
{
public int Id { get; init; }
}
Init only setters provide consistent syntax to initialize members of an object. Property initializers make it clear which value is setting which property. The downside is that those properties must be settable.
With that, you don't need to provide the value at the beginning and the constructor and you can do it afterward:
var myClass = new MyClass
{
Id = 10
}
and it will be sealed and you cannot change it anymore.
myClass.Id = 43; // not allowed
read more info
In a nutshell:
var obj = new MyClass
{
Id = 42 // totally fine
};
obj.Id = 43; // not OK, we're not initializing
Trivial in this case and not much different to using a constructor parameter, but useful in some more complex scenarios where you don't want 200 constructor parameters, but you do want it to be outwardly immutable once constructed.
This question already has answers here:
How to get a property value using reflection
(2 answers)
C# Reflection - Get field values from a simple class
(3 answers)
how to get both fields and properties in single call via reflection?
(6 answers)
Closed 3 years ago.
What I'm trying to do is have a class that I can inherit from and be able to track changes to properties.
I have this base class called TrackedEntity.
I then create another class TestEntity that inherits from TrackedEntity.
On my TestEntity class I have marked one of my fields with an attribute that I called CompareValues.
TrackedEntity
public class TrackedEntity {
public void GetCompareValues<T> () {
var type = typeof (T);
var properties = type.GetProperties ();
foreach (var property in properties) {
var attribute = (CompareValues[]) property.GetCustomAttributes
(typeof(CompareValues), false);
var hasAttribute = Attribute.IsDefined (property, typeof
(CompareValues));
}
}
}
TestEntity
public class TestEntity : TrackedEntity
{
public int one { get; set; }
[CompareValues]
public int two { get; set; }
public int three { get; set; }
}
CompareValues attribute:
[AttributeUsage ( AttributeTargets.Property |
AttributeTargets.Field,
Inherited = true)]
public class CompareValues : Attribute {
public CompareValues () { }
}
I can then do this
var test = new TestEntity ();
test.GetCompareValues<TestEntity> ();
In my GetCompareValues method I can find which fields in TestEntity use my CompareValues attribute.
I am trying to find a way to access the value of the fields that have the CompareValues attribute so that I can track the changes and log information about it.
If there is any other way to get this done by using another method please let me know.
Thank you.
You´re almost there. All you need to do is to get the properties value on the current instance - the instance on which you´ve called the method:
if(hasAttribute)
{
var value = property.GetValue(this, null);
}
Apart from this you won´t need generics here. Just use this:
var type = this.GetType();
which returns TestEntity in case of the instance being of your derived type.
This question already has answers here:
Convert List<DerivedClass> to List<BaseClass>
(13 answers)
Closed 3 years ago.
I am trying to make a dictionary of lists of derived objects. My solution was to use classes for each object that implemented the same base interface. The issue is that interface must have the property of the list of the object its designated to contain. That property must allow me to store each one of the derived classes without data loss from the objects.
I've tried down casting the lists and putting them straight into the dictionaries. I've tried making wrapper classes and down casting the base property to the proper list also.
public class Body
{
Dictionary<string, List<BodyPart>> parts;
public Body(List<Arms> arms_, List<Head> head_) //etc
{
parts = new Dictionary<string, List<BodyPart>>()
{
{"arms", arms_},
{"head", head_}
//etc
}
}
}
problem with this solution is that the lists of specific derived body parts will not cast to a list of the base class BodyPart. The other issue is that I'm also certain that because this is down casting it will cause data loss as I will only be able to reference the objects as the base class.
I expect the result to be a dictionary of different body parts that I can reference without data loss.
You must convert the lists
Dictionary<string, List<BodyPart>> parts;
public Body(List<Arms> arms_, List<Head> head_) //etc
{
parts = new Dictionary<string, List<BodyPart>>()
{
{"arms", new List<BodyPart>(arms_)},
{"head", new List<BodyPart>(head_)}
//etc
}
}
The reason is this: assume that you could insert a List<Head> into the dictionary. Then you retrieve it with
List<BodyPart> bodyParts = parts["head"];
and add it arms
bodyParts.Add(new Arms()); // Oops! this is a List<Head>.
Therefore a List<Derived> is not assignment compatible to a List<Parent>. Maybe it would just be simpler to type all these lists as List<BodyPart>, even when they contain Arms and Heads.
This new List<BodyPart>(head_) woks, because the constructor accepts an IEnumerable<BodyPart> as parameter. An IEnumerable<T> is read-only. Therefore the list (which implements IEnumerable<Head>) you pass as argument will only be read and its elements will be added to a List<BodyPart>, which is okay.
See: Covariance and Contravariance (C#)
Try something like this :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<BodyPart> arms = new List<BodyPart>() { new BodyPart() { name = "Left Arm" }, new BodyPart() { name = "Right Arm" } };
List<BodyPart> head = new List<BodyPart>() { new BodyPart() { name = "Head" } };
new Body(arms, head);
}
}
public class Body
{
Dictionary<string, List<BodyPart>> parts = new Dictionary<string, List<BodyPart>>();
public Body(List<BodyPart> arms_, List<BodyPart> head_) //etc
{
parts.Add("arms", arms_);
parts.Add("head", head_);
}
}
public class BodyPart
{
public string name { get; set; }
}
}
This question already has answers here:
Convert List<DerivedClass> to List<BaseClass>
(13 answers)
Closed 3 years ago.
I have a class that have a property (SearchResults) that need to be List<T>, where T is one of my search classes depend on a condition
public class SearchGeneralResponse : ActionResponse
{
public IList<ISearchRecord> SearchResults { get; set; }
public SearchGeneralResponse(MbsObjectType searchType)
{
if(searchType == MbsObjectType.SourceRepo) SearchResults = new List<SearchRecord>();
if(searchType == MbsObjectType.BuildConfiguration) SearchResults = new List<SearchRecordBuild>();
}
}
I can cast new SearchRecord to ISearchRecord. But when I do it with list
this.SearchResults = new List<SearchRecord>();
I get this error:
Cannot implicitly convert type System.Collections.Generic.List 'SearchRecord' to System.Collections.Generic.List 'ISearchRecord'
Here's my interface:
public interface ISearchRecord
{
}
And one of the derived classes:
public class SearchRecord : ISearchRecord
{
public string Name { get; set; }
public string Summary { get; set; }
}
How can I create a List<T> property that can be initialized to a list of a class depending on a certain condition?
Add a cast to your initializer:
this.SearchResults = new List<SearchRecord>().Cast<ISearchRecord>().ToList();
Generics provide compile-time type safety, but in this case you're trying to tell the compiler that it should just trust you that there won't be run-time problems. Its job is to not trust you :)
Consider what would happen if this assignment were allowed and you did this:
IList<ISearchRecord> results; // results is of type IList<ISearchRecord>
results = new List<SearchRecord>(); // but it holds a value of type List<SearchRecord>
results.Add(new SomeOtherSearchRecord()); // ERROR
Since the property SearchResults is of type IList<ISearchRecord>, any code which uses that property can assign any implementation of ISearchRecord to an element of that list. So it needs to always be ISearchRecord and not a more specific implementing type.
Step back and consider the semantics of what your code needs to do. Should SearchResults support any implementation of ISearchRecord? If it's always going to be assigned from SearchRecord then make it that specific type:
public IList<SearchRecord> SearchResults { get; set; }
Or, if it needs to be a list of ISearchRecord (so it can support other implementations) then you'd have to create the list of that type:
this.SearchResults = new List<ISearchRecord>();
Edit: Also, if your new List<>() is just a contrived example and you're actually getting the list from somewhere else, you still need to create a new list. Fortunately the references within that list can still be to the same objects, but the list itself needs to be the correct compile-time type. You could achieve this with:
this.SearchResults = someOtherList.Cast<ISearchRecord>().ToList();
This would create a new list object, of the correct type, containing the same elements as someOtherList.