I have been battling with this bit of code for a while now and I am trying to get a solution as it is literally the last part before it goes to testing.
I have the following interfaces and classes (simplified to the relevant parts):
public interface ITagParent<T> where T : ITag
{
List<TagAddOn<T>> TagCollection { get; set; }
}
public interface ITag
{
int Id { get; set; }
string Description { get; set; }
TagGroup TagGroup { get; set; }
}
public class TagAddOn<T> : ViewModelBase where T : ITag
{
private T _currentTag;
public T CurrentTag
{
get { return _currentTag; }
set { _currentTag = value; }
}
}
public partial class Customer : ITagParent<CustomerTag>
{
List<TagAddOn<CustomerTag>> _tagCollection;
public List<TagAddOn<CustomerTag>> TagCollection
{
get { return _tagCollection; }
set { _tagCollection = value; }
}
}
public partial class CustomerTag : ITag
{
public int Id { get; set; }
}
public class TagAddOnManager
{
public static string GetTagCurrentValue(List<TagAddOn<ITag>> dataObjectAddOns)
{
// LOTS OF SNIPPING!
return string.Empty;
}
}
I am trying to use the GetTagCurrentValue method in the TagAddOnManager class like this:
string value = TagAddOnManager.GetTagCurrentValue(
((ITagParent<ITag>)gridCell.Row.Data).TagCollection));
Everything compiles fine, but errors when trying to cast gridCell.Row.Data to ITagParent<ITag>. I understand this is due to covarience and a workaround (if not a terribly safe one) is to mark T in the ITagParent interface with the out keyword, but that won't work as you can see it is used in the TagCollection property, which can't be read only.
I tried casting the above to ITagParent<CustomerTag>, but this fails at compile time with a 'cannot convert' error when trying to feed it into my GetTagCurrentValue method.
Another option I considered is using some base classes instead of the ITagParent interface, but that won't work as the Customer object already inherits from another base class, which can't be modified for this implementation.
I know I could just overload the GetTagCurrentValue method with List<TagAddOn<CustomerTag>> as the parameter type and all other variations, but that really seems like a 'I give up' solution. I could probably use reflection to get the desired results, but that would be unwieldy and not very efficient, especially considering this method could be called a lot in a particular process.
So does anyone have any suggestions?
Could you use something like that
public class TagAddOnManager
{
public static string GetTagCurrentValue<TTag>(ITagParent<TTag> tagParent)
where TTag : ITag
{
// Just an example.
return tagParent.TagCollection.First().CurrentTag.Description;
}
}
and use it like that?`
var value = TagAddOnManager.GetTagCurrentValue((Customer)CustomergridCell.Row.Data);
Related
I have a problem with designing my interfaces
I have these interfaces :
interface IField {
}
interface IScreenField : IField {
}
interface ITable {
CustomCollection<IField> CustomCollection { get; set; }
}
interface IScreen
{
AnotherCustomCollection<IScreenField> AnotherCustomCollection { get; set; }
}
IScreen interface should inherit from ITable but it shows an error that I have to implement a collection of IField but I already implement a collection of IScreenField
What is the soltuion for this ?
I uploaded a sample project to explain the issue more
You can check the error message in Screen class that says :
Screen does not implement interface member ITable.Fields. Screen.Fields cannot implement ITable.Fields becuase it does not have the matching return type of CusomCollection<IField>
Here is the sample :
Sample project
This description of this example helps you to solve the problem: If IExample2 inherits another Interface, when implementing IExample2 u need to implement
all the method(properties etc...) that has been declared in interface + the method of inhered interfaces from IExample2. Remember that when you implement an interface you have to implement all of members of that interface (you have to implement even the members of all interfaces that are in chain) and all the returns types has to be the same in interface and in class.
interface IExample
{
void Method1();
}
interface IExample2 : IExample
{
void Method2();
}
class Screen : IExample2
{
public void Method2()
{
}
public void Method1()
{
}
}
Chain Example
interface IExample
{
void Method1();
}
interface IExample2 : IExample
{
void Method2();
}
interface IExample3 : IExample2
{
void Method3();
}
This is the answer I posted on your previous post. Reposting it here as-is since your previous question was put on hold before I could
submit the answer.
It’s very difficult to identify the problem without looking at the full code but based on what you have said, I believe, you have implemented IScreenField explicitly and the compiler is not able to find any implementation of IField.
Checkout following for more info:
https://www.codeproject.com/Articles/1000374/Explicit-Interface-VS-Implicit-Interface-in-Csharp
Update: After looking at the code
First of all you need to understand difference between Implicit and Explicit implementations of an Interface:
Implicit: you access the interface properties and properties as if they were part of the class.
Explicit: you can only access properties and properties when treating the class as the implemented interface.
The problem with the Screen class is that it implements IScreen interface, which in-turn implements ITable interface. Both these interfaces have a property named Fields.
The problem surfaced due to this and you are required to
explicitly implement the Fields property in Screen class.
NOTE: It is irrelevant that you have different return types. Since you have implemented Fields property in both interfaces, it is assumed that you are expecting different values when the property is accessed from each of the interfaces.
public class Screen : IScreen
{
public string Name { get; set; }
AnotherCustomCollection<IBaseField> IScreen.Fields
{
get
{
return default(AnotherCustomCollection<IBaseField>);
}
}
CustomCollection<IField> ITable.Fields
{
get
{
return default(CustomCollection<IField>);
}
}
public string Title { get; set; }
public string Description { get; set; }
}
Now how to access them? To access Fields property of each of these Interfaces you need to access Screen object as those interfaces.
Ex:
var screen = new Screen();
var fields = screen.Fields; // Error
var fields = (screen as IScreen).Fields; // returns property value of IScreen Fields
var fields = (screen as ITable).Fields; // returns property value of ITable Fields
Here is the complete code: https://dotnetfiddle.net/5KS0Xd
Hope this was helpful. All the best and happy coding.
You could do something like this:
public class Screen : IScreen
{
public string Name { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public AnotherCustomCollection<IBaseField> Fields { get; set; }
CustomCollection<IField> ITable.Fields
{
get
{
throw new System.NotSupportedException();
}
}
}
And apparently the compiler likes that, and if you do something like this:
public static void Main(string[] args)
{
var collection = new List<IScreen>()
{
new Screen
{
Fields = new AnotherCustomCollection<ScreenInterface.IBaseField>
{
new TextField()
{
Name = "Hello"
}
}
}
};
var y = collection.First();
//Prints "Hello"
Console.WriteLine(string.Join(" ", y.Fields.Select(x => x.Name)));
Console.ReadLine();
}
But, if you are working with the upper interface (ITable)
public static void Main(string[] args)
{
var collection = new List<ITable>() //here
{
new Screen
{
Fields = new AnotherCustomCollection<ScreenInterface.IBaseField>
{
new TextField()
{
Name = "Hello"
}
}
}
};
var y = collection.First();
//Throws NotSupportedException
Console.WriteLine(string.Join(" ", y.Fields.Select(x => x.Name)));
Console.ReadLine();
}
My guess is that there isn't the concept of generic inheritance, and that may be proved if you switch the conditional generic parameter of AnotherCustomCollection from IBaseField to IField, and instead of throwing the exception, return the public Fields property on Screen.ITable.Fields. Compiler will automatically recognize the concrete property and everything will work.
So, for this to work, either define an implicit operator or a custom getter:
public class Screen : IScreen
{
public string Name { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public AnotherCustomCollection<IBaseField> Fields { get; set; }
CustomCollection<IField> ITable.Fields
{
get
{
var customCollection = new CustomCollection<IField>();
customCollection.AddRange(Fields);
return customCollection;
}
}
}
Lets say i have a class
public class Transfer
{
prop1
prop2
....
public List<SubTransfer> SubTransfers { get; set; }
}
Which i get from a function that connects to a database
Now i want to have a class that adds a status, both to the Transfer and to each one of the SubTransfer.
One question is if i should use inheritance here? or composition?
I think inheritance, so im trying to do something like this:
public ExtendedSubTransfer : SubTransfer
{
public StatusEnum Status { get; set; }
}
public ExtendedTransfer : Transfer
{
public StatusEnum Status { get; set;}
}
My problem is i dont know how to do that ill get a list of ExtendedSubTransfer when using ExtendedTransfer.
I know i can override SubTransfers using the keyword new like this:
public new List<ExtendedSubTransfers> SubTransfers {get; set;}
Is it "legit"? Or do you have other suggestions?
Thanks for the help!
It will compile but it probably isn't going to do what you want. Keep in mind that List<ExtendedSubTransfer> does not extend List<SubTransfer>. For example, if you have any operation that uses the base class you will not get what you want. To demonstrate, let us pretend the base class has an ID and you want to print the IDs.
public void PrintIds()
{
ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
PrintSubTransferIds(extendedTransfer);
}
private PrintSubTransferIds(Transfer transfer)
{
foreach(var subTransfer in transfer.SubTransfers)
{
Console.WriteLine(subTransfer.Id);
}
}
The above method will not work unless you do something very strange when loading the items from the database. For example, if your loading code looks like...
public GetExtendedTransfer(...)
{
ExtendedTransfer result = new ExtendedTransfer();
List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
result.SubTransfers = subTransfers;
return result;
}
Then it will not work. It will not print any subtransfer ids because transfer.SubTransfers will be an empty list. Instead you'd have to do something weird when loading from the database like...
public GetExtendedTransfer(...)
{
ExtendedTransfer result = new ExtendedTransfer();
List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
result.SubTransfers = subTransfers;
Transfer subtypedResult = result;
subtypedResult.SubTransfers = subTransfers.Cast<SubTransfer>();
return result;
}
Also, the following case would be a compile time error:
public void PrintIds()
{
ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
PrintSubTransferIds(extendedTransfer.SubTransfers);
}
private PrintSubTransferIds(List<SubTransfer> subTransfers)
{
foreach(var subTransfer in subTransfers)
{
Console.WriteLine(subTransfer.Id);
}
}
This would fail to compile because extendedTransfer.SubTransfers is of type List<ExtendedSubTransfer> which cannot be assigned to List<SubTransfer>.
Update: So what should you do?
C# (4.X and above) allows covariance on certain interfaces such as IReadOnlyList (C# 4.5 and above). Thus you can do...
public class Transfer
{
public virtual IReadOnlyList<SubTransfer> SubTransfers { get; private set; }
public void SetSubTransfers(List<SubTransfer> subTransfers)
{
SubTransfers = subTransfers;
}
}
public class ExtendedTransfer
{
private List<ExtendedSubTransfer> _subTransfers;
public override IReadOnlyList<SubTransfer> SubTransfers
{
get { return _subTransfers; }
}
public void SetSubTransfers(List<ExtendedSubTransfer> subTransfers)
{
_subTransfers = subTransfers;
}
}
This would be my best attempt at solving your problem. However, you didn't mention how you are getting your entities from the database. I don't think EntityFramework would be very happy with this field arrangement by default.
I'm having an issue with implementing parent/child interfaces when both of them are generic. The best answer I've been able to find is that it isn't possible, but I also haven't been able to find anyone else asking the exact same question. I'm hoping that I just don't know the right syntax to make the compiler understand what I'm trying to do. Here is a stripped down example of the code I'm trying to implement.
public interface I_Group<T>
where T : I_Segment<I_Complex>
{
T Segment { get; set; }
}
public interface I_Segment<T>
where T : I_Complex
{
T Complex { get; set; }
}
public interface I_Complex
{
string SomeString { get; set; }
}
public partial class Group : I_Group<Segment>
{
private Segment segmentField;
public Group() {
this.segmentField = new Segment();
}
public Segment Segment {
get {
return this.segmentField;
}
set {
this.segmentField = value;
}
}
}
public partial class Segment : I_Segment<Complex> {
private Complex complexField;
public Segment() {
this.complexField = new Complex();
}
public Complex Complex {
get {
return this.c_C001Field;
}
set {
this.c_C001Field = value;
}
}
}
public partial class Complex : I_Complex {
private string someStringField;
public string SomeString {
get {
return this.someStringField;
}
set {
this.someStringField = value;
}
}
}
So here, Complex is the grandchild, which implements I_Complex without error. Segment is its parent, which implements I_Segment without error. The issue is with the grandparent, Group, trying to implement I_Group. I get the error
The type 'Segment' cannot be used as type parameter 'T' in the generic type or method 'I_Group<T>'. There is no implicit reference conversion from 'Segment' to 'I_Segment<I_Complex>'.
I am led to believe this is an issue with covariance, but I was also led to believe this was something that was supposed to work in C# 4.0. This works when the child isn't generic, which leads me to think that there must exist some syntax to get this to compile properly. Am I doing something wrong? Is this even possible? And if not, could someone help me understand why not?
You can add second generic type parameter into I_Group interface declaration:
public interface I_Group<T, S>
where T : I_Segment<S>
where S : I_Complex
{
T Segment { get; set; }
}
And specify explicitly both types in Group class declaration:
public partial class Group : I_Group<Segment, Complex>
It will make your code compile.
Well, to get covariance or contravariance to work with an interface, you use the "in" and "out" keywords. Covariance uses the out keyword, for example:
public interface A<out T>
{
T Foo();
}
While contravariance uses the in keyword:
public interface B<in T>
{
Bar( T t );
}
The problem in your case is that your I_Segment interface is not covariant or contravariant, so I_Segment is not compatible with I_Segment, which is why you get a compile error.
When I define an interface that contains a write-only property:
public interface IModuleScreenData
{
string Name { set; }
}
and attempt to (naively) implement it explicitly with an intention for the property to also have a publicly available getter:
public class ModuleScreen : IModuleScreenData
{
string IModuleScreenData.Name { get; set; }
}
then I get the following error:
Error 'IModuleScreenData.Name.get' adds an accessor not found in
interface member 'IModuleScreenData.Name'
The error is more or less expected, however, after this alternative syntax:
public class ModuleScreen : IModuleScreenData
{
public string Name { get; IModuleScreenData.set; }
}
has failed to compile, I suppose that what I am trying to do is not really possible. Am I right, or is there some secret sauce syntax after all?
You can do this:
public class ModuleScreen : IModuleScreenData
{
string IModuleScreenData.Name
{
set { Name = value; }
}
public string Name { get; private set; }
}
On a side note, I generally wouldn't recommend set-only properties. A method may work better to express the intention.
You can't change the how the interface is implemented in the inheriting class. That is the whole point.. if you need to do something new with a property you could make a new property that references the inherited properties specific implementation. Interfaces are there so you can conform to a specified standard for object inheritance.
UPDATE:
On second thought.. you should be able to just do this.... this will compile fine:
public class ModuleScreen : IModuleScreenData
{
public string Name { get; set; }
}
I have a 3rd party badly designed library that I must use.
It has all sorts of types it works with, we'll call them SomeType1, SomeType2 etc.
None of those types share a common base class but all have a property named Value with a different return type.
All I want to do is to be able to Mixin this class so I'll be able to call someType1Instance.Value and someType2Instance.Value without caring what the concreate type it is and without caring what the return type is (I can use object).
So my code is currently:
public interface ISomeType<V>
{
V Value {get; set;}
}
public interface ISomeTypeWrapper
{
object Value { get; set; }
}
public class SomeTypeWrapper<T> : ISomeTypeWrapper
where T : ISomeType<???>
{
T someType;
public SomeTypeWrapper(T wrappedSomeType)
{
someType = wrappedSomeType
}
public object Value
{
get { return someType.Value; }
set { someType.Value = value != null ? value : default(T); }
}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
The problem is that I don't know what T might be until runtime due to the fact that I get a dictionary of objects.
I can iterate the dictionary and use reflection to create a SomeWrapperType on runtime but I would like to avoid it.
How can I mixin the concreate type of SomeType to ISomeType?
How can I know what V type parameter is? (wish I had typedefs and decltype like in c++)
How can I, with the minimum of use of reflection possible Mixin those classes with the interface/base class?
You could try the Duck Typing Extensions for Windsor. It means you will need to register each of your types.
container
.Register(Component.For(typeof(SomeType1)).Duck<ISomeType>())
.Register(Component.For(typeof(SomeType2)).Duck<ISomeType>());
You could probably use linq and the register AllTypes syntax to reduce code if the names are similar.
Alternatively in the short term create a factory which can return you the objects you need, implement a concrete object for each type. No you are using the interface you can remove the factory at a later date and replace it with something else with minimal impact:
public class SomeTypeWrapperFactory
{
public ISomeType<int> CreateWrapper(SomeType1 someType1)
{
return new SomeType1Wrapper(someType1);
}
public ISomeType<string> CreateWrapper(SomeType2 someType2)
{
return new SomeType2Wrapper(someType2);
}
}
public class SomeType1Wrapper : ISomeType<int> { ... }
public class SomeType2Wrapper : ISomeType<int> { ... }
Regardless of how you implement the wrapper, be the individually or using a god like class you have the ability to change how the wrapping is done and keep the rest of your code clean.
Why SomeTypeWrapper but not SomeObjectWrapper?
public class SomeObjectWrapper : ISomeType
{
Object _someObject;
PropertyInfo _valuePropertyInfo;
public SomeObjectWrapper(Object wrappedSomeObject)
{
_someObject = wrappedSomeObject;
_valuePropertyInfo = _someObject.GetType().GetProperty("Value", System.Reflection.BindingFlags.Public);
}
public object Value
{
get { return _valuePropertyInfo.GetValue(_someObject, null); }
set { _valuePropertyInfo.SetValue(_someObject, value, null); }
}
}
Edited With .NET 3.5 using LinFu
You may use LinFu instead of Castle. However, you would be using reflection anyway, both with Castle's and with Linfu's DynamicProxy, only hidden in the guts of the libraries instead of being exposed in your code. So if your requirement to avoid the use of reflection is out of performance concerns, you wouldn't really avoid it with this solution.
In that case I would personally choose Orsol's solution.
However: here's an example with LinFu's ducktyping.
public interface ISomeType {
object Value{get; set;}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeWrapperFactory
{
public static ISomeType CreateSomeTypeWrapper(object aSomeType)
{
return aSomeType.CreateDuck<ISomeType>();
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
foreach(var o in someTypes)
{
Console.WriteLine(SomeTypeWrapperFactory.CreateSomeTypeWrapper(o).Value);
}
Console.ReadLine();
}
}
Since you don't know the type of the SomeType's until runtime, I would not use mixins, but the visitor pattern (I know this doesn't answer the question on how to use mixins for this, but I just thought I'd throw in my 2 cents).
With .NET 4 using dynamic
See Bradley Grainger's post here on using c#4's dynamic keyword to implement the visitor pattern.
In your case, reading all the "Value" properties from your dictionary of SomeType's could work like this:
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeVisitor
{
public void VisitAll(object[] someTypes)
{
foreach(var o in someTypes) {
// this should be in a try-catch block
Console.WriteLine(((dynamic) o).Value);
}
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
var vis = new SomeTypeVisitor();
vis.VisitAll(someTypes);
}
}