How to work with generic <T> with EntitySet<T> - c#

I have a opteration that needs to run on three types of EntitySets; however, the data for each type is the same. Linq-to-SQL is creating these three types to match up with a few between, "tween" tables in my database.
Is there a way to work with generic EntitySet types like I've got them below?
private EntitySet<T> GetClientHorizontal(EntitySet<T> clientHorizontal) {}
It is to solve the redundant issue like below.
private EntitySet<LeafHorizontal>
GetClientLeafHorizontal(EntitySet<LeafHorizontal> clientLeafHorizontal) { }
private EntitySet<BayHorizontal>
GetClientBayHorizontal(EntitySet<BayHorizontal> clientBayHorizontal) { }
private EntitySet<SideliteHorizontal>
GetClientSideliteHorizontal(
EntitySet<SideliteHorizontal> clientSideliteHorizontal) { }

If you are saying that these three classes are almost the same - then you can create an interface or base class with common members:
interface IHorizontal
{
int SuperValue { get; set; }
}
Then you need to inherit LeafHorizontal, BayHorizontal and SideliteHorizontal classes from this interface:
public partial class LeafHorizontal : IHorizontal { ... }
public partial class BayHorizontal : IHorizontal { ... }
public partial class SideliteHorizontal : IHorizontal { ... }
After that you can create generic method:
private EntitySet<T> GetClientBayHorizontal(EntitySet<T> clientBayHorizontal) where T : IHorizontal
{
clientBayHorizontal.SuperValue++;
}

Related

Create base classes with base class lists

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 { }

Overloading methods while using Generics with base classes

I have the following Classes:
public abstract class Gear<T> : ScriptableObject, IGear { ... }
public class Armor : Gear<ArmorStatsLevel> { ... }
public class Weapon : Gear<WeaponStatsLevel> { ... }
Now I had the following methods to list my instances:
public abstract class WidgetListArmor {
public void ActionSelected(Armor gear) {
if (...) GameSession.Equip(gear);
}
}
public abstract class WidgetListWeapon {
public void ActionSelected(Weapon gear) {
if (...) GameSession.Equip(gear);
}
}
Because this was kind of redundant, I thought of moving it all to a base clase:
public abstract class WidgetListGear<T> : MonoBehaviour {
public void ActionSelected(T gear) {
if (...) GameSession.Equip(gear);
}
}
public class WidgetListArmors : WidgetListGear<Armor> { ... }
public class WidgetListWeapons : WidgetListGear<Weapon> { ... }
And while this seems cleaner, I have a new problem now. Because T is a Generic, GameSession.Equip can't overload gear.
Did I chose a bad pattern to organize my code? Am I missing something from Generics that allows me to do this operation?
UPDATE
Here is the GameSession signatures:
public class GameSession {
public static bool Equip(Armor armor);
public static bool Equip(Weapon weapon);
}
Make Weapon and Armor implement an interface called IGear, for example:
public interface IGear
{ }
public class Weapon : IGear
{
//snip
}
public class Armor : IGear
{
//snip
}
Constrain the generic type to IGear:
public abstract class WidgetListGear<T> : MonoBehaviour
where T : IGear
{
public void ActionSelected(T gear) {
if (...) GameSession.Equip(gear);
}
}
And make GameSession.Equip take IGear as the parameter type.
What you're looking for is dynamic dispatch. I would suggest you try the following:
GameSession.Equip((dynamic)gear);
However, I don't think it's the best idea since you've tried to encode your Game rules in type system and right now you're starting a mini-compiler in runtime to perform a dispatch for you.
I'd like to point you to Eric Lippert's articles on that subject. Looks like you have similar issues with what he's described.
Part 4 describes the dynamic approach I've provided as well as its disadvantages. Part 5 provides a completely different approach. Overall, I highly recommend reading each part.

Declaring Method with generic type

I was using generic types in C# and I am new to using generic types. So, right now I am stuck with a problem. I have some classes like these:
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T>
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
//What will be the syntax of declaring this method
//The syntax of the following method is wrong and incomplete.
//It's there just to give an idea about whai i want to do.
public void MyMethod<T>()
where T : BaseClass<..what to write..>
{
}
}
My question is what will be the correct syntax of declaring MyMethod if I want to call MyMethod like this:
MyMethod<ChildClass1>();
If I understood correctly, you try to filter "MyMethod" so that T is a class of type "ChildClass ...".
You can add a generic parameter to your function like this:
public void MyMethod<T, U>()
where T : BaseClass<U>
{
}
But then you have to call MyMethod in that way.
MyMethod<ChildClass1, MyModel1>();
So it's quite complicated to use.
Another solution is to create a new "blank" class :
public abstract class Base // mark it as abstract if you don't need to use it in your code
{
}
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T> : Base //The class inherits the new class
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
public void MyMethod<T>()
where T : Base
{
}
}
You've forgotten to mention the return type and adding <T> after the class name. For example, if the return type is void, you could declare the method as:
public void MyMethod<T>()
where T : BaseClass<T>
{
}
This will work (by which I mean it compiles)
public void MyMethod<T>()
where T : BaseClass<MyModel1>
{ }
so does this:
public void MyMethod<T>()
where T : ChildClass1
{ }
Further edit after reading your comment...
You can do this:
public class AnotherClass<TBaseClass, TModel> where TBaseClass : BaseClass<TModel>
{
public void MyMethod(TBaseClass input)
{ }
}
I have a term for this, hopefully non-offensive. I call it The Generic Rabbit Hole of Madness. It's what happens when we try to combine generics and inheritance so that one set of classes can accomplish a broad set of goals that become increasingly confusing, and we solve it by adding more generic parameters and more generic classes.
You reach the bottom of the hole if you
- use <dynamic>
- check to see what the actual type is using GetType(), typeof, or is
- get it to compile but can't remember what it's supposed to do

Calling Generic Method on Generic Field?

I have the following and at some point I need to create Failures for Validations. We suppose each type deriving from Validation has one and only one type deriving from Failure<T> where T is the aforementioned implementation of Validation.
As I have a growing number of implementations of Validation, I need to be able to instantiate the right type deriving from Failure<T>, and call the link method on it within a method that looks like
void recordFailureForValidation(Validation v) {
Type failureType = dict[v.GetType()];
Object failure = Activator.CreateInstance(failureType);
// how do I call failure.link(v) ?
}
At Runtime, a dictionary gives me the type deriving from Failure<T> given T.
I am able to instantiate Failure<T> (Failure1, Failure2, etc...), but I can't find how to call link on the public field reference of my newly created Failure instance (by making all uses that made sense to me of GetMethod, MakeGenericMethod, Invoke, etc...)
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
public abstract class Failure<T>
where T : ValidationRule, new() {
...
public MyReferenceClass<T> reference;
...
}
public class Failure1 : Failure<Validation1> {
}
public class Failure2 : Failure<Validation2> {
}
public abstract class ValidationRule {
...
}
public class ValidationRule1 : ValidationRule {
...
}
public class ValidationRule2 : ValidationRule {
...
}
link is private since you do not specify a different accessibility. Make it public or internal:
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
then you can call it from Failure<T> through the reference property:
public abstract class Failure<T>
where T : ValidationRule, new()
{
protected T Validation {get; set;};
public MyReferenceClass<T> reference;
}
public class Failure1 : Failure<Validation1>
{
public void Test()
{
this.reference.link(Validation);
}
}
Let Failures implement a non generic IFailure interface as well as a generic one in the same manner as IEnumerable and IEnumerable<T>
Create an abstract factory method within ValidationRule that has to be implemented by each concrete Validation
public ValidationRule1 : ValidationRule
{
public override IFailure ToFailure()
{
return new Failure1(this);
}
...
}

Generic Constructors and Inheritance

I have a generic class with a class constraint on it.
public class MyContainer<T> where T : MyBaseRow
MyBaseRow is an abstract class which I also want to contain a member of some flavour of MyContainer.
public abstract class MyBaseRow
{
public MyContainer<MyBaseRow> ParentContainer;
public MyBaseRow(MyContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
I am having problems with the constructors of classes inherited from MyBaseRow eg.
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(MyContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}
Won't allow MyInheritedRowA in the constructor, the compiler only expects and only allows MyBaseRow. I thought the generic class constraint allowed for inheritance? What am I doing wrong here and is there any way I can redesign these classes to get around this?
Many thanks in advance for any responses.
Basically, you can't use generics that way, because the covariance system doesn't work that way with classes. See here: http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx
You can however use an interface like this:
public interface MyContainer<out T> where T : MyBaseRow {
}
And that code will compile.
You can make a covariant generic interface (C#4.0):
public interface IContainer<out T> where T : MyBaseRow
{
}
public class MyContainer<T> : IContainer<T> where T : MyBaseRow
{
}
public abstract class MyBaseRow
{
public IContainer<MyBaseRow> ParentContainer;
public MyBaseRow(IContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(IContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}

Categories