I have a need to create a couple of classes that will serve as base classes for some data functionality I want to implement.
The first, we'll call SessionObjectDataItem looks like this ...
public class ObjectSessionDataItem
{
public int ID { get; set; }
public bool IsDirty { get; set; }
public bool IsNew { get; set; }
public bool IsRemoved { get; set; }
}
And next I want a List called ObjectSessionDataList and this is where I get stuck.
I can create the class OK ...
public class SessionObjectDataList<SessionObjectDataItem> : List<SessionObjectDataItem>
{
}
where I fall down is trying to define properties on the list that access items in it. For example, I want to write...
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
but VS refuses to recognise the SessionObjectDataItem property IsDirty inside the List object definition.
What I'm trying to end up with is a case where I might define
public class AssociatedDocument : SessionObjectDataItem
{
...
}
public class DocumentList : SessionObjectDataList
{
}
And then be able to say...
DocumentList list = new DocumentList();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Can I actually do what it is that I'm attempting? Am I just doing it wrong?
Generic constraints will help here; you can write a container-class for which the generic type-parameter is constrained to be SessionObjectDataItem or one of its subtypes. This will allow you to construct a generic class that can hold instances of a specific sub-type of SessionObjectDataItem.
public class SessionObjectDataList<T> : List<T> where T : SessionObjectDataItem
{
public SessionObjectDataList<T> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
}
Usage:
var list = new SessionObjectDataList<AssociatedDocument>();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Try to use the generic version Where<T> of the queryable interface:
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.AsQueryAble().Where<SessionObjectDataItem>(d => d.IsDirty).ToList();
}
}
Else Where simply assumes d as type Object.
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.
I've found couple of questions on the same topic here, however I couldn't find what I need. Basically I am searching for this kind of magic:
public class BaseClass
{
public int DerivedТype { get; set; }
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
DerivedТype = 1;
Property = initialValue;
}
public T Property { get; set; }
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
DerivedТype = 2;
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public float OtherProperty { get; set; }
}
public class Program
{
public static void Main()
{
List<BaseClass> baseClassList = new List<BaseClass>();
baseClassList.Add(new DerivedClass<int>(5));
baseClassList.Add(new OtherDerivedClass<float>(6));
foreach (var derived in baseClassList)
{
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
}
}
}
I want a list of BaseClass where I can insert instances of DerivedClass and OtherDerivedClass. So far so good.
DerivedClass and OtherDerivedClass hold different properties so I really have no idea how access them. Also I don't want to use any weired casts. So this part of the code prevents me from building.
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
Any ideas would be appreciated. Thank you in advance!
This looks like a problem that can be solved with polymorphism. I'll make a version of your app that does exactly what you seem to be doing in your example, but if there was more information as to what your target goal is, the solution may be different.
public abstract class BaseClass
{
public abstract void DoSomething();
public abstract void GetData(Dictionary<string,string> container);
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
public override void DoSomething()
{
Console.WriteLine(Property);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(Property), "{Property}");
}
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public override void DoSomething()
{
Console.WriteLine(OtherProperty);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(OtherProperty), "{OtherProperty}");
container.Add(nameof(OtherProperty2), "{OtherProperty2}");
}
}
Your foreach loop could then be as simple as:
foreach(var derived in baseClassList) derived.DoSomething();
This is the proper way to do something like this using OO. There's no need for the DerivedType integer since the object knows what type of class it is and what to do. This is why one would use polymorphism. It's simple and elegant and OO. Extend or change the DoSomething to be more appropriate for what you're trying to do.
The OP came up with his own solution, but if the goal is to do something with the data that is more meaningful, you could also pass in an object to an abstract method that allows you to do this. I added a GetData method that will return all of the property values as strings. The second type of the dictionary could also be object with the actual value stored in the dictionary.
BaseClass could also be a regular class with a method in it to return an IDictionary of object values with string keys. The method could use reflection to get all property values for whatever class it is the base of. Reflection has much more overhead, though, so is not the most efficient way to do this from an execution standpoint.
The correct way to check if an object is a certain type is to use the is operator such as:
if(derived is DerivedType<int>)
{
// Do what you need to do with the specific object type
}
If you know you're going to cast the object, as pointed out by Adosi, you would use:
var castedValue = derived as DerivedType<int>;
if(castedValue != null)
{
// Do what you need to do with castedValue
}
A null will be returned if the object isn't of type DerivedType<int>. Trying to use (DerivedType)derived would cause an invalid cast exception.
To the best of my knowledge what you want is between impossible and not a good idea. Typechecking is done at compile time. Stuff like Dynamic can move those checks to runtime, but it results in all kinds of issues (functions that take dynamic parameters also return dynamic).
If you got at least C# 7.0, you can at least write a switch for it. Old switch only supported values vs constants for a few select value types and string. But C# 7.0 introduces pattern matching. With that you could even use a is check as part of a case.
Thank you all for the awesome support! I decided to go simple and just use a cast.
public class BaseClass
{
public int DataТype { get; set; }
public object Data { get; set; }
}
public class DataClass<T>
{
public DataClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
List<BaseClass> listBaseClass = new List<BaseClass>();
BaseClass dummy = new BaseClass();
dummy.DataТype = 1;
dummy.Data = new DataClass<int>(50);
listBaseClass.Add(dummy);
if (listBaseClass[0].DataТype == 1)
{
DataClass<int> casted = (DataClass<int>)listBaseClass[0].Data;
Console.WriteLine(casted.Property);
}
}
}
Is it possible to add different type of generic objects to a list?. As below.
public class ValuePair<T>
{
public string Name { get; set;}
public T Value { get; set;
}
and let say I have all these objects...
ValuePair<string> data1 = new ValuePair<string>();
ValuePair<double> data2 = new ValuePair<double>();
ValuePair<int> data3 = new ValuePair<int>();
I would like to hold these objects in a generic list.such as
List<ValuePair> list = new List<ValuePair>();
list.Add(data1);
list.Add(data2);
list.Add(data3);
Is it possible?
In general, you'd have to either use a List<object> or create a non-generic base class, e.g.
public abstract class ValuePair
{
public string Name { get; set;}
public abstract object RawValue { get; }
}
public class ValuePair<T> : ValuePair
{
public T Value { get; set; }
public object RawValue { get { return Value; } }
}
Then you can have a List<ValuePair>.
Now, there is one exception to this: covariant/contravariant types in C# 4. For example, you can write:
var streamSequenceList = new List<IEnumerable<Stream>>();
IEnumerable<MemoryStream> memoryStreams = null; // For simplicity
IEnumerable<NetworkStream> networkStreams = null; // For simplicity
IEnumerable<Stream> streams = null; // For simplicity
streamSequenceList.Add(memoryStreams);
streamSequenceList.Add(networkStreams);
streamSequenceList.Add(streams);
This isn't applicable in your case because:
You're using a generic class, not an interface
You couldn't change it into a generic covariant interface because you've got T going "in" and "out" of the API
You're using value types as type arguments, and those don't work with generic variable (so an IEnumerable<int> isn't an IEnumerable<object>)
Not unless you have a non-generic base-type ValuePair with ValuePair<T> : ValuePair (it would work for an interface too), or use List<object>. Actually, though, this works reasonably:
public abstract class ValuePair
{
public string Name { get; set; }
public object Value
{
get { return GetValue(); }
set { SetValue(value); }
}
protected abstract object GetValue();
protected abstract void SetValue(object value);
}
public class ValuePair<T> : ValuePair
{
protected override object GetValue() { return Value; }
protected override void SetValue(object value) { Value = (T)value; }
public new T Value { get; set; }
}
No, it is not possible. You could create, in your case, a base class ValuePair from which ValuePair<T> derives. Depends on your purposes.
it's not possible as far as I know.
the line:
List<ValuePair> list = new List<ValuePair>();
you wrote in your sample is not providing a concrete type for T and this is the issue, once you pass it, you can only add object of that specific type.
I'm designing a data layer for several classes, and I want each of these classes to follow a contract I set up with IMyDataItem:
public delegate void ItemChangedHandler(object sender, EventArgs e);
public interface IMyDataItem<T> {
string Insert { get; }
int Save();
string Select { get; }
string Update { get; }
}
That being done, I now want to include a base class that my other classes all inherit from.
How would I fix this base class?
public class MyDataItem : IMyDataItem<T> {
private const string TODO = "TODO: This has not been done.";
public const int NOT_SET = -1;
private bool changed;
internal int rowId;
public MyDataItem() {
changed = false;
rowId = NOT_SET;
}
public ItemChangedHandler OnChange;
internal void notify() {
changed = true;
if (OnChange != null) {
OnChange(this, new EventArgs());
}
}
public int RowID {
get { return rowId; }
set {
if (rowId != value) {
rowId = value;
notify();
}
}
}
public bool SaveNeeded { get { return changed; } }
public static virtual T Load() {
return default(T);
}
public virtual string Insert { get { return TODO; } }
public virtual string Select { get { return TODO; } }
public virtual string Update { get { return TODO; } }
public virtual int Save() {
changed = false;
return NOT_SET;
}
}
The errors are all in the second class MyDataItem (my base class):
Type or namespace name 'T' could not be found - on the first line where I declare my class.
I tried removing the errors by adding a where clause to the signature:
public class MyDataItem : IMyDataItem<T> where T : MyDataItem {
However, this presented me with the error:
Constraints are not allowed on non-generic declarations
Is there a way to do what I am after, or will I need to stick with simpler class designs?
When the base class is complete, other classes such as Location, Employee, and Record will inherit it.
Well to fix that particularly compile time error you would need:
public class MyDataItem<T> : IMyDataItem<T>
However, without knowing more about what you're trying to achieve, it's hard to recommend an alternative approach.
Why not drop the <T> from the interface and make it non-generic? The T is not used in the interface.
Otherwise, if you want the class to be generic, say
public class MyDataItem<T> : IMyDataItem<T>
But again, if T is not used, what's your reason to declare it?
What you are attempting to do is somewhat similar to what I've also done. I've wanted some generic code applicable to all my "data manager" instances but also wanted to apply stronger typing to them... In a similar fashion...
public interface iMyDataManager
{
stuff ...
}
public class MyDataManager<T> : iMyDataManager
{
implementation ... that I want common to all derived specific instances
}
public class MySpecificDataInstance : MyDataManager<MySpecificDataInstance>
{
continue with rest of actual implementations specific to this class.
}
I did not see any reason use generic in your implementation.
Secondary, are you sure about parameters of these functions:
string Insert { get; }
int Save();
string Select { get; }
string Update { get; }
Why Update and Insert returns parameters? Are you sure, you will able remember meaning of this within 2 months?
I have a helper class that does a simple but repetitive process on a List of entities. For simplicity, it's like this...
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
I now need to add support for another type, but everything is identical... how do I avoid an increasing list of overloaded methods like this:
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
public static List<MyOtherType> DoSomethingSimple(List<MyOtherType> myOtherTypes) {
return myOtherTypes.Where(myOtherType => myOtherType.SomeProperty.Equals(2)).ToList();
}
... and so on.
Here's two ways:
Use generics, and a common base class
Use interfaces
Method 1:
public class BaseClass
{
public int SomeProperty { get; set; }
}
public class MyType : BaseClass { }
public class MyOtherType : BaseClass { }
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : BaseClass
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Method 2:
public interface ICommon
{
int SomeProperty { get; set; }
}
public class MyType : ICommon
{
public int SomeProperty { get; set; }
}
public class MyOtherType : ICommon
{
public int SomeProperty { get; set; }
}
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : ICommon
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Now, if you try to make the method use the interface directly, like this:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(List<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Then that would work if you have a List<ICommon> when you call it, but won't work if you have a List<MyType>. In C# 4.0 this can be done if we change the method slightly:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(IEnumerable<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Note that I changed to using an IEnumerable<ICommon> instead. The concept here is called Co- and contra-variance, and beyond that I'm not going to say much about it. Search Stack Overflow for more information on the subject.
Tip: I would change the input parameter to be IEnumerable<T> regardless, since this would make your method usable in more instances, you could have different types of collections, arrays, etc. and as long as they contain the right type, they can be passed to the method. By limiting yourself to List<T> you force the user of your code to convert to a list in some cases. My guidelines are to be as unspecific as possible in input parameters, and as specific as possible in output parameters.
Assuming the property has the same name and type for each list type, you could add an interface containing the property and implement it for each type you want to call this method on:
public interface ISomeProperty
{
object SomeProperty { get; }
}
DoSomethingSimple could then be:
public static List<T> DoSomethingSimple<T>(IEnumerable<T> list) where T : ISomeProperty
{
return list.Where(i => i.SomeProperty.Equals(2)).ToList();
}