How would you approach this design? - c#

I have ControlA which accepts an IInterfaceB which has a property of type
List<unknownType>
In an event of ControlA i need to add a new instance of unknownType to the List in IInterfaceB...
unknownType needs specific properties so i immediately thought it could be an interface, but quickly realised interfaces cannot be instantiated...
How would you design this system?
EDIT the current inheritance chain looks like this:
topLevelClass -> baseObject -> IBaseObject (which is implemented in topLevelClass)
so if i added a new class to the chain it would need to do the inheriting and implementing which would be impossible (afaik)

If I'm interpreting this correctly, you could add a constraint on unknownType to be of some interface that contains the properties you need:
class ControlA
{
void Frob<T>(IInterfaceB<T> something) where T : IHasSomeProperties, new()
{
something.ListOfT.Add(new T() { SomeProperty = 5 });
something.ListOfT.Add(new T() { SomeProperty = 14 });
}
}

Would a restriction on the type work?
List<T> where T : IInterface

Your specification isn't specific enough to answer well, but try putting constraints on T.
public interface IInterfaceB<T>
where T : new()
{
List<T> Whatever { get; }
}
This allows you to do this:
T iDoNotCare = new T();

Why does List have to be an unknowntype? Why can't it be a real class, the has the real properties you need with a constructor for you to instantiate? If you need to extend that class, you can then inherit from it. Based on the information you're providing, if all you need is a few properties in the class that goes into this List, then a good old class should do the trick.

Related

Reference specific class from its generic base class

When working with generics if I have for example a class:
class Foo<T> where T:Cheese
{
}
and then 2 derived classes
class FooDerivedBlue:Foo<BlueCheese>
{
}
class FooDerivedWhite:Foo<WhiteCheese>
{
}
where BlueChesse and WhiteCheese inherit from chesse.
Now there is another class, that will conditionally use FooDerivedBlue or FooDerivedWhite.
The class should have a property like
public Foo<Cheese> Foo {get;set;}
so I can set it to the FooDerivedXXX I need at runtime.
When doing this an trying to set Foo=new FooDerivedWhite() the compiler will complain, since FooDerivedWhite cant be converted to Foo<cheese>.
A more practical example:
If I have a
ArticleRepository<T>
AssemblyArticleRepository:ArticleRepository<AssemblyArticle>
ProductionArticleRepository:ArticleRepository<ProductionArticle>.
ProductionArticle and AssemblyArticle inherit from Article.
Both specific repositories inherit from ArticleRepository and have a lot of common logic. There are certain parts I need only access to the logic they shared (for example adding a new item or deleting it) and in order to avoid duplicate code, I want to instantiate the proper repo and pass it.
For example, I could have an ArticleService, which I pass a type and it instantiates the right repository. Instead, I would need to have a service for each Article type. (??- with my actual knowledge)
Which is the way to solve it in .NET? Or maybe I am facing the problem/writing my code in a wrong way?
Update Here a gist with the concrete problem:
https://gist.github.com/rgomez90/17ec21a1a371be6d78a53a4072938f7f
There are a few ways to deal with this, but the most straightforward is probably to make your "other class" also have a generic type parameter that describes what kind of cheese it operates on. Then all the types can be statically correct.
public abstract class Cheese { }
public class BlueCheese : Cheese { }
public abstract class CheeseTool<T> where T:Cheese { }
public class BlueCheeseTool : CheeseTool<BlueCheese> { }
public class CheeseEater<T> where T : Cheese {
public T Cheese;
public CheeseTool<T> Tool;
}
Then all typing is statically correct:
CheeseEater<BlueCheese> eater = new CheeseEater<BlueCheese>();
eater.Cheese = new BlueCheese();
eater.Tool = new BlueCheeseTool();
More complicated solutions might involve explicit casts and type factories, but simplest is best if it does the job.

Preventing inheritance of static member

Base:
public abstract class systemClient : IDisposable
{
public static List<systemClient> Collection = new List<systemClient>();
[...]
}
derived class
public class station : systemClient
{
[...]
}
In this setup I can access station.Collection.
Question is:
Is there a way to hide station.Collection ?
You can't. By creating inhClass as a subclass of baseClass inhClass must provide everything that baseClass provides. Otherwise baseClass x = new inhClass() would be invalid.
In this specific case though you have made the method static, that means that it doesn't actually have its own copy of the method. inhClass is just accessing the static one within baseClass.
I agree with Tim B answer. You can't simply "ignore" some methods or properties of a class which you inherits. But, what you can do is implementing an interface, which may do the work you want. For further reading, take a look here.

PropertyGrid - Collection Edition / Wrapper

I have a complex kind of property I want to edit in a PropertyGrid.
interface IInterface{}
abstract class Base : IInterface{}
class A : Base{}
class B : Base{}
These class represent what can be stored in the property (The content of these class does not matter).
// The Property to be displayed in the PropertyGrid
class Property
{
List<Base> MyListOfObjects {get;set;}
}
I managed to create a derived class of System.ComponentModel.Design.CollectionEditor which allows me to add different kind of datas, using [Editor(typeof(MyCollectionEditor), typeof(UITypeEditor))] attribute in the collection property.
class MyCollectionEditor : CollectionEditor
{
public MyCollectionEditor(Type type) : base(type)
{
}
#region Overrides of CollectionEditor
protected override Type[] CreateNewItemTypes()
{
base.CreateNewItemTypes();
// [EDIT assembly, see below]
var types = (from t in Assembly.GetAssembly(typeof(IInterface)).GetTypes()
where t.GetInterfaces().Contains(typeof (IInterface)) && !t.IsAbstract
select t).ToArray();
return types;
}
protected override Type CreateCollectionItemType()
{
return typeof(A); // 1st problem
}
}
First Problem: The only solution I found to be able to edit the objects is to give a concrete child class type in CreateCollectionItemType(). Why? How to avoid that?
Second Problem: I now want to use a wrapper to give this property to the propertyGrid item. Instead of having the property attributes ([Category("General")] for instance) in the model, I want to put them in a wrapper.
It works fine for everything but the collection.
Here is how I did it:
class abstract WrapperBase<T>
{
T WrappedObject{get;set;}
}
class PropertyWrapper:WrapperBase<Property>
{
List<Base> MyListOfObjects
{
get{return WrappedObject.MyListOfObjects;}
set{WrappedObject.MyListOfObjects=value;}
}
}
With this, the collection editor won't let me add objects to this Collection, and the dropdown that was available to add a specific kind of object is gone.
Any idea? Thanks in advance!
[EDIT]
The second part of the problem is solved: Since the wrapper is located in another assembly, I was not looking in the right place for the implementations of IInterface.
CreateNewItemTypes is good. in CreateCollectionItemType return the base type. i think that should work.

How to retrieve the argument of a generic base class at compile time? (i.e., without using Reflection)

I want to implement a generic method to retrieve header/detail data from a database:
public static T RetrieveHeaderDetail<T>
where T : Header<???>, new()
// Where ??? means "what can I do here?"
{
// ...
}
Here is the definition of the generic representing a document header:
public class Header<TDetail> where TDetail : class, new()
{
public List<TDetail> Details;
}
And here are some instantiations:
public class RequestForQuotation : Header<RequestForQuotationDetail> { ... }
public class Order : Header<OrderDetail> { ... }
public class Invoice : Header<InvoiceDetail> { ... }
// ..
It is not hard to prove that, since .NET does not allow either multiple inheritance or "generic specialization" (which would allow a Header<U> to derive from some other Header<V>), for any specific T, there is at most one U such that T inherits (directly or indirectly) from Header<U>. Moreover, it is trivial to find the type U: iterate over T's base types until you find an instance of Header<U>, and then just take the generic's argument! Still, C# wants me to specify the change my method's definition to the following:
public static T RetrieveHeaderDetail<T,U>
where T : Header<U>, new()
where U : class, new()
{
// ...
}
Is there any way to get around this problem? I know it would be possible using Reflection, but I think it is a good practice to never do at runtime what could be done at compile time.
When I hit problems like this, I really, really miss C++.
I asked this question not too long ago.
Generics with Generic Parameters and Abstract class
I'm not sure I fully understand what you're after, but could you define an interface and use it to specify the constraint?
For example, we have something like this in a couple places:
public class Reader<T> where T : IInt32Id
{
public T GetById(int Id)
{
// get by id
}
}
Then I just use IInt32Id as an interface to derive all of my classes that have an int (as opposed to long) ID field.

How to get the type of derived class at base class without generics?

My base class use reflection on derived classes to provide some functionality to them. Currently I do it this way:
abstract class BaseClass<T>
{
string GetClassString()
{
// Iterate through derived class, and play with it's properties
// So I need to know the type of derived class (here T).
return result;
}
static bool TryParse(string classString, out T result)
{
// I should declare a variable as T and return it
}
}
Can I do this without generics ?
Edit:
Sorry, you want the type parameter (ie typeof(T)).
In that case you still use this.GetType() but you add .GetGenericArguments()[0] after.
Try parse:
You need to create a new instance of a type you don't know
There are two ways:
First, without changing the rest, with the Activator class and the following code:
result = (T) Activator.CreateInstance(typeof(T))
(MSDN).
Then, you could add a "new" constraint to your type:
MyClass<T> where T : new() {...}
result = new T();
Both samples require parameter less constructors. If you want to pass parameters, then you need to go deeper inside System.Reflection, get the list of constructors and call the one you want. A factory pattern may also do the job.

Categories

Resources