i've got base and derived classes as follows (this is just an example):
class Base_TripLog {
public List<Base_Trip> trips = ...
public Base_TripLog(string log_filename) {
// load stuff into trips
}
}
class Base_Trip {
public string vehicle_id = ...;
public Dictionary<ulong, Base_Waypoint> waypoints = ...
public Base_Trip() {
}
public add_waypoint(ulong epoch_sec, Base_Waypoint waypoint) {
waypoints.Add(epoch_sec, waypoint);
}
}
class Base_Waypoint {
/// time and gps coords
}
class Derived_TripLog : Base_TripLog {
public string company_name;
public new List<Derived_Trip> trips = ...
public Derived_TripLog(string company_name, string filename) : base(filename) {
this.company_name = company_name;
if (trips.Count > 0) {
// do stuff
}
}
}
class Derived_Trip : Base_Trip {
public int duration_sec;
public Derived_Trip() : base() {
duration = compute_trip_duration(waypoints)
}
}
the Derived_TripLog constructor uses the base constructor to load the file of waypoints. trips in the derived class will naturally still be empty. i was planning to copy base.trips into the derived trips.
two question:
is copying the standard way to handle this situation? if the base Trip class had lots of members and collections, it could be it pain to copy all the members.
if copying is the standard approach, then i'm essentially doubling memory usage. (base.trips can be quite large.) it seems i could just do base.trips.Clear() to free up those resources. if there a correct way?
That´s what generics are for. Instead of having a list of trips of different types in every child-class, you have a single list with the generic type within your base-class:
class Base_TripLog<TripType> where TripType: Base_Trip {
public List<TripType> trips = ...
public Base_TripLog(string log_filename) {
// load stuff into trips
}
}
Now you can just inherit this class using the correct generic argument:
class Derived_TripLog : Base_TripLog<Derived_Trip>
{
public string company_name;
public Derived_TripLog(string company_name, string filename) : base(filename)
{
this.company_name = company_name;
if (trips.Count > 0) {
// do stuff
}
}
This way you don´t need to re-declare the property for every class, but just have a single definition for all types that derive from Base_Trip.
Related
I have a method as below
List<Customer> GetCusts = dataContext.Customers;
The customers table has a field called IsValued so i can do something like this
foreach (var c in GetCusts)
{
if(c.IsValued)
{
// do something
}
}
I have a products table doing the exact same thing also with the same column name
List<Product> GetProds = dataContext.Products;
foreach (var p in GetProds)
{
if(p.IsValued)
{
// do something
}
}
I thought to turn this into a Generic method (or better a class), so i can pass in a generic list a bit like
foreach (var p in GetData) // GetData could be a List<t> but of course i cant cast it.
{
if (p.IsValued)
{}
}
but of course IsValued does not exist. I know the reason why (due to it being a generic type) but after researching around to see if its possible i couldnt get a decent example and test it out or maybe i just didnt understand. Can anyone advise how this could be possible or lead me to an article to achieve this?
Edit 1
My attempt so far in a class, it could be wrong but to give an idea in case im on the wrong path. I assume i need a property of IsValued (which doesnt have to be of a bool value) in the GenericValue class?
public interface ICustomGenerics<T>
{
IEnumerable<T> GetData();
}
public class GenericValue<T> : ICustomGenerics<T> where T : class
{
public IEnumerable<T> GetAll()
{
_entities.
}
}
Here is how you can use an interface:
public interface IValued {
bool IsValued { get; set; }
}
public class Customer : IValued {
public bool IsValued { get; set; }
}
public class Product : IValued {
public bool IsValued { get; set; }
}
public void filterData<T>(List<T> data) where T: IValued {
foreach (var d in data) {
if (d.IsValued) {
}
}
}
As others pointed out you can either pick a base class and derive from that, or you can use an interface. I'd rather go with the interface in this case.
Assuming you are using Entity Framework, you can use a partial classes to apply your interface:
public interface IValuable
{
bool IsValued { get; set; }
}
and you'd have partial classes like:
public partial class Customer : IValuable
{
// IValuable implementation
public bool IsValued { get; set; }
}
public partial class Product : IValuable
{
// IValuable implementation
public bool IsValued { get; set; }
}
Now you can have a processor / service class that accepts these as generics with a condition that they should all implement this interface:
public class Processor<T> where T : IValuable
{
public Something Process(T parameter)
{
foreach (var p in GetData)
{
if (p.IsValued)
{
// Do stuff
}
}
}
}
Since you declared your generic to have IValuable implementation, the code below will know IsValuable is a member.
I suggest this approach over base classes because interfaces are best used this way to define common behaviour. You can even see the same pattern in the framework, IDisposable (which implements Dispose()) and IEnumerable / IEnumerator (which implements things like GetEnumerator(), MoveNext() etc) are two most common examples.
In short, I'm hoping to achieve a kind of barebones structure in one place and implement/define in another. I want to better "see" the interconnectedness without all the functionality clouding it up mostly for design discussions, explanations, etc. I could do this with inheritance, but I really don't want to change all the names of everything just to achieve this. Is this a thing somehow?
// Simple File for seeing relationships between classes
public class AllMyObjectTypes // A class because it will be its own object with functionality below all this structural stuff
{
public class Thing1
{
public Thing2[] things2;
public Thing3[] things3;
}
public class Thing2[]
{
public int version;
public Thing1[] thing1Utilizers;
}
public class Thing3[]
{
public string Title;
}
}
// Complicated file for doing all the hard work for Thing1 with all the internal variables to make it happen.
public class Thing1 : Thing1 // Implement itself somehow?
{
// Stuff I want to use and define but not cloud the structure above
private int[] internalStuff;
private string moreInternalStuff;
public void UsefulFunctionButWantSeparated()
{
// Hundreds of lines of code clouding junk up
}
}
Interface & Class declarations
public interface IThing
{
IThing2[] Thing2s();
string DoSomething();
}
public class Thing : IThing
{
private readonly IThing2[] _thing2s = new IThing2[1] { new Thing2() };
public IThing2[] Thing2s() => _thing2s;
public string DoSomething()
{
return "MyText";
}
}
public interface IThing2
{
}
public class Thing2 : IThing2
{
}
Use
IThing thing;
thing = new Thing();
var thing2s = thing.Thing2s();
var txt = thing.DoSomething();
Partial Classes is exactly what I was looking for, but it did require that I don't nest within another class. Unless maybe I made that partial too...? But either way, this gets me closest to my goal
// Simple File for seeing relationships between classes
//public class AllMyObjectTypes // A class because it will be its own object with functionality below all this structural stuff
//{
public partial class Thing1
{
public Thing2[] things2;
public Thing3[] things3;
}
public partial class Thing2[]
{
public int version;
public Thing1[] thing1Utilizers;
}
public partial class Thing3[]
{
public string Title;
}
//}
// Complicated file for doing all the hard work for Thing1 with all the internal variables to make it happen.
public partial class Thing1 // More implementation
{
// Stuff I want to use and define but not cloud the structure above
private int[] internalStuff;
private string moreInternalStuff;
public void UsefulFunctionButWantSeparated()
{
// Hundreds of lines of code [no longer] clouding junk up
}
}
I have Bills and Receipts. Both types have a property called Lines, but Receipt.Lines is full of ReceiptLines and Bill.Lines is full of BillLines. I'd like them to both inherit from a class called Document with a property Lines that's full of DocumentLines so that I can occasionally pass them to functions that operate on Documents, but I don't want to have to myReceipt.Lines.Select(line => (ReceiptLine)line) each time I am specifically using a Bill or Receipt. Is there an elegant way to do this?
Note that the following attempt results in CS1503 Argument 1: cannot convert from 'Receipt' to 'Document<DocumentLine>'
void Main()
{
var something = new Receipt();
DoStuff(something);
}
public void DoStuff(Document<DocumentLine> document) { }
public abstract class DocumentLine { }
public class BillLine : DocumentLine { }
public class ReceiptLine : DocumentLine { }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { }
public class Receipt : Document<ReceiptLine> { }
Note that you cannot change a type when overriding, but you can make the line type a generic parameter.
public abstract class DocumentLine { ... }
public class BillLine : DocumentLine { ... }
public class ReceiptLine : DocumentLine { ... }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { ... }
public class Receipt : Document<ReceiptLine> { ... }
Deriving the line types from a common base has advantages. 1) you can reuse stuff common to both line types. 2) You can limit the actual types of TDocLine. This safer as it disallows you to specify an inappropriate type and it allows you to access the common members declared in DocumentLine from other methods in the Document<TDocLine> class.
You could use a generic type to define the List item type, like so:
interface DocumentLine { }
class BillLine : DocumentLine { }
class ReceiptLine : DocumentLine { }
class Document<T> where T : DocumentLine
{
public List<T> Lines { get; set; }
}
class Bill : Document<BillLine> { }
class Receipt : Document<ReceiptLine> { }
Edit: What the new implied question is referring to is called 'Generic Covariance'. In C# generic covariance is limited to interface and delegate types [see out keyword (generic modifier)].
Instead, to get the behavior you want, you'll have to carry the generic variable as generic with conditions, rather than a fixed covariant type.
public void DoStuff<T>(Document<T> document) where T : DocumentLine { }
I would like to declare a generic field inside PakFileFormat class in order to be replaceable with concrete types in derived classes.
This will be fine:
public class Pak10File : PakFileFormat
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}
How to fix this ?
Thanks.
Related classes
public abstract class PakFileEntry { }
public class Pak10FileEntry : PakFileEntry
{
public long size; // 8 bytes
public long csize; // 8 bytes
public long offset; // 8 bytes
public byte fname_len; // 1 byte
public char[] fname; // variable
}
public class PakFileToc<T> where T : PakFileEntry { }
public abstract class PakFileFormat
{
protected PakFileToc<T>; // ----- This does not compile.
}
You would need to make PakFileFormat generic also in order to make that compile.
In order for this to be useful though, you will probably need to make PakFileFormat implement some kind of non-generic interface.
It is hard to give more detail than this without knowing exactly what you need PakFileFormat to actually do, or how it will be used.
public abstract class PakFileFormat<TPakFile> where TPakFile : PakFileEntry
{
protected PakFileToc<TPakFile> toc;
}
The sub-classes would then look something like:
public class Pak10File : PakFileFormat<Pak10FileEntry>
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}
I wrote the following console app to test static properties:
using System;
namespace StaticPropertyTest
{
public abstract class BaseClass
{
public static int MyProperty { get; set; }
}
public class DerivedAlpha : BaseClass
{
}
public class DerivedBeta : BaseClass
{
}
class Program
{
static void Main(string[] args)
{
DerivedBeta.MyProperty = 7;
Console.WriteLine(DerivedAlpha.MyProperty); // outputs 7
}
}
}
As this console app demonstrates, the MyProperty property exists once for all instances of BaseClass. Is there a pattern to use which would allow me to define a static property which will have allocated storage for each sub-class type?
Given the above example, I would like all instances of DerivedAlpha to share the same static property, and all instances of DerivedBeta to share another instance of the static property.
Why am I trying to do this?
I am lazily initializing a collection of class property names with certain attributes (via reflection). The property names will be identical for each derived class instance, so it seems wasteful to store this in each class instance. I can't make it static in the base class, because different sub-classes will have different properties.
I don't want to replicate the code which populates the collection (via reflection) in each derived class. I know that one possible solution is to define the method to populate the collection in the base class, and call it from each derived class, but this is not the most elegant solution.
Update - Example of what I'm doing
At Jon's request, here's an example of what I'm trying to do. Basically, I can optionally decorate properties in my classes with the [SalesRelationship(SalesRelationshipRule.DoNotInclude)] attribute (there are other attributes, this is just a simplified example).
public class BaseEntity
{
// I want this property to be static but exist once per derived class.
public List<string> PropertiesWithDoNotInclude { get; set; }
public BaseEntity()
{
// Code here will populate PropertiesWithDoNotInclude with
// all properties in class marked with
// SalesRelationshipRule.DoNotInclude.
//
// I want this code to populate this property to run once per
// derived class type, and be stored statically but per class type.
}
}
public class FooEntity : BaseEntity
{
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_A { get; set; }
public int? Property_B { get; set; }
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_C { get; set; }
}
public class BarEntity : BaseEntity
{
public int? Property_D { get; set; }
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_E { get; set; }
public int? Property_F { get; set; }
}
Desired end result
Accessing FooEntity.PropertiesWithDoNotInclude returns a List<string> of:
{
"Property_A",
"Property_C"
}
Accessing BarEntity.PropertiesWithDoNotInclude returns a List<string> of:
{
"Property_E"
}
Two possible approaches:
Use attributes; decorate each subclass with an attribute, e.g.
[MyProperty(5)]
public class DerivedAlpha
{
}
[MyProperty(10)]
public class DerivedBeta
{
}
That only works when they're effectively constants, of course.
Use a dictionary:
var properties = new Dictionary<Type, int>
{
{ typeof(DerivedAlpha), 5) },
{ typeof(DerivedBeta), 10) },
};
EDIT: Now that we have more context, Ben's answer is a really good one, using the way that generics work in C#. It's like the dictionary example, but with laziness, thread-safety and simple global access all built in.
Jon has a good solution as usual, although I don't see what good attributes do here, since they have to be explicitly added to every subtype and they don't act like properties.
The Dictionary approach can definitely work. Here's another way to do that, which explicitly declares that there will be one variable per subclass of BaseEntity:
class FilteredProperties<T> where T : BaseEntity
{
static public List<string> Values { get; private set; }
// or static public readonly List<string> Values = new List<string>();
static FilteredProperties()
{
// logic to populate the list goes here
}
}
The drawback of this is that it's rather difficult to pair with a GetType() call such as you might use in methods of BaseEntity. A Dictionary, or wrapper thereto which implements lazy population, is better for that usage.
I just recently needed this same thing and came across this question. I think Jon's and Fried's ideas to use a Dictionary are on the right track but don't quite hit what I was looking for so I thought I'd show my own complete and very easy to extend implementation.
public class TypeStaticProperty<T>
{
T _defaultValue;
Dictionary<Type, T> _values = new Dictionary<Type, T>();
public TypeStaticProperty(T defalutValue = default)
{
_defaultValue = defalutValue;
}
public T Get(object caller)
{
lock (_values)
{
if (_values.TryGetValue(caller?.GetType(), out T val))
return val;
else
return _defaultValue;
}
}
public void Set(object caller, T val)
{
lock (_values)
_values[caller?.GetType()] = val;
}
}
And to demonstrate:
class TestBaseClass
{
static TypeStaticProperty<int> _property = new TypeStaticProperty<int>();
public int Property
{
get => _property.Get(this);
set => _property.Set(this, value);
}
}
class TestClass1 : TestBaseClass
{
}
class TestClass2 : TestBaseClass
{
}
class Program
{
static void Main(string[] args)
{
TestClass1 test1a = new TestClass1();
TestClass1 test1b = new TestClass1();
test1a.Property = 1;
test1b.Property = 2;
TestClass2 test2a = new TestClass2();
TestClass2 test2b = new TestClass2();
test2a.Property = 3;
test2b.Property = 4;
Console.WriteLine($"test1a.Property = {test1a.Property}");
Console.WriteLine($"test1b.Property = {test1b.Property}");
Console.WriteLine($"test2a.Property = {test2a.Property}");
Console.WriteLine($"test2b.Property = {test2b.Property}");
}
}
Output:
test1a.Property = 2
test1b.Property = 2
test2a.Property = 4
test2b.Property = 4
So while you still need a class instance to access and set the property, the value will always be the same across all instances of that precise type. (This includes generics too; Foo<int> will be seen as a different type than Foo<string>). This has the huge advantage over Fried's example in that you don't need to know at compile time the precise type whose "static" value you're looking for when accessing or setting.
PS - For full disclosure, this was heavily inspired by the WPF source code, which uses a very similar pattern for DependencyProperty's and all kinds of other internal bells and whistles designed to improve performance and reduce memory footprint.