I have a method ABC() which gets called from two different places in my application. And from both places I have different objects of class which is implemented a common interface "IDestination".
My two classes and Interface are looking like this:
public class ClassA: IDestination
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
}
public class ClassB: IDestination
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
public string Var4 { get; set; }
public string Var5 { get; set; }
}
public interface IDestination
{
string Var1 { get; set; }
string Var2 { get; set; }
}
As of now Method ABC() accepts the object of classA, I want it can also accept the object of classB. For this I have made my method defination generic like below:
public string ABC<T>(T obj)
{
}
But, the problem is inside the ABC method I want to access the properties of classes (classA and classB both).
public string ABC<T>(T obj)
{
//Some code
obj.var2; //of classA
obj.var4; //of classB
//Some code
}
And I can't allowed to do any changes in the interface.
How can I achieve this? I do not want to create another method for handling different class objects. Any idea?
First of all, interfaces aren't inherited but implemented.
In the other hand, generic parameters can be constrained:
public string ABC<T>(T obj) where T : IDestination
OP said:
And I can't allowed to do any changes in the interface.
BTW, with your requirement and just with generic type constraints you won't be able to accept both classA and classB because C# doesn't support multi-inheritance. If you want to access classB members, you'll need to expand your IDestination interface to define all properties you want to access in a classB typed as IDestination:
public interface IDestination
{
string Var1 { get; set; }
string Var2 { get; set; }
string Var3 { get; set; }
string Var4 { get; set; }
string Var5 { get; set; }
}
Or you can define a second interface with the rest of properties:
public interface IDestination2
{
string Var3 { get; set; }
string Var4 { get; set; }
string Var5 { get; set; }
}
...and you'll implement it on classB:
public class ClassB: IDestination, IDestination2
Anyway, the problem here is that you can't constraint a generic parameter to accept two different inheritances of some given classes. That is, for example, if you constraint T to be both IDestination and IDestination2, you won't be able to give ClassA as argument, because it doesn't implement IDestination2.
OP said:
I do not want to create another method for handling different class objects.
Actually this could be also solved without generics but with method overloading and it's not an evil approach even when you don't want to go this route:
public void ABC(IDestination destination) {}
public void ABC(IDestination2 destination) {}
// or directly...
public void ABC(ClassA destination) {}
public void ABC(ClassB destination) {}
Otherwise, you'll need to implement this as follows:
public string ABC<T>(T obj) where T : IDestination
{
ClassA a = obj as ClassA;
ClassB b = obj as ClassB;
// Now if you want to access Var1, Var2 you can access them
// using "obj" reference, because T is IDestination
string var1 = obj.Var1;
string var2 = obj.Var2;
if(a != null)
{
// Here access all ClassA members...
}
if(b != null)
{
// Here access all ClassB members...
}
}
For me, above approach is a design flaw. If I use generic types and interfaces is because I want to work with objects that equal the typing of the generic type parameter.
If I start to perform downcasts to particular implementations of the interface, it's like defeating the purpose of using IDestination and it seems like your method could be just accepting object because your method will access ClassA and ClassB members instead of IDestination ones:
public string ABC(object obj)
{
ClassA a = obj as ClassA;
ClassB b = obj as ClassB;
// Now if you want to access Var1, Var2 you can access them
// using "obj" reference, because T is IDestination
string var1 = obj.Var1;
string var2 = obj.Var2;
if(a != null)
{
// Here access all ClassA members...
}
if(b != null)
{
// Here access all ClassB members...
}
return "";
}
TL;DR
In summary, you should use interfaces to type your objects and generic constraints to guarantee a minimum typing on your references in order to avoid casts. Otherwise, generic typing isn't your solution.
You should definitly re-think your design. When your method accepts instances of the interface it should work for all types, not only a set. Imagine you create a third type that also implements the interface. You would have to re-implement the whole method to support this. Therefor all the properties should be defined on the interface instead of the class-level and then can be accessed within the method.
However if you really have to use your current approach you can simply cast it to the appropriate type:
ClassA a = obj as ClassA;
if (a != null) a.Var2 = ...
// this will fail if a user provides an instance of ClassC which also implements the interface
else ((ClassB)obj).Var4 = ...
For this to work you will also need a constraint on your gegernic parameter:
public string ABC<T>(T obj) where T : IDestination
I think that a better design is the following:
public string ABC<T>(T obj) where T : IDestination
{
}
I say so, because since you want a generic method for object that implements the IDestination interface, it would be better as a design, If you have declared it as constraint. For this, please have a look here.
Then in order you access the field that you want in the ABC, the interface should have all this properties. So If we assume that you want both classes A and B have the same three properties Var1, Var2 and Var3 and you want to access them in the ABC, then you have t redecclare your interface as below:
public interface IDestination
{
string Var1 { get; set; }
string Var2 { get; set; }
string Var3 { get; set; }
}
You can use the reflection class to handle that problem, you can get the properties of parameter in the runtime and you can use also.
Type type = typeof(obj);
PropertyInfo[] propertyList = type.GetProperties();
Well, to achieve what you want you need to implement the ABC method to accept a type of IDestination:
public string ABC<T>(T obj) where T : IDestination
But for that to work, you then have to change your interface to have all the methods you want to access:
public interface IDestination
{
string Var1 { get; set; }
string Var2 { get; set; }
string Var3 { get; set; }
string Var4 { get; set; }
string Var5 { get; set; }
}
Then you have to change your classes to implement all the members of the interface which means you might end up with something like this:
public class ClassA : IDestination
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
public string Var4
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public string Var5
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
public class ClassB : IDestination
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
public string Var4 { get; set; }
public string Var5 { get; set; }
}
But it doesn't make a lot of sense to have the extra methods implemented in ClassA if they just throw an exception. So you might as well just fully implement them. But then ClassA and ClassB are identical. So you have to ask yourself what is unique enough about each class to justify a separate concrete implementation of IDestination? Answering that question will guide you on what to do.
EDIT:
Since you can't change the interface, are you forced to use the interface in method ABC? Can you create an abstract class that both ClassA and ClassB inherit from?
public abstract class ClassAB : IDestination //might not need the interface
{
public virtual string Var1 { get; set; }
public virtual string Var2 { get; set; }
public virtual string Var3 { get; set; }
public virtual string Var4 { get; set; }
public virtual string Var5 { get; set; }
}
public class ClassA : ClassAB
{
//override any of the virtual methods needed
}
public class ClassB : ClassAB
{
//override any of the virtual methods needed
}
Then change ABC method:
public string ABC(ClassAB classAB)
{
//all the methods are available on classAB
}
Both ClassA and ClassB would still be of type IDestination because the abstract parent class implements it. The only question is if you can change method ABC to expect a type of ClassAB instead of IDestination?
I think it will be hard to handle type-specific properties in generic method as it doesn't know what is the specifics of such properties. I would recommend delegating this logic to a method, that the classes will implement via interface.
As you mentioned in your comment, you can't change the interface IDestination and you don't want to break the compatibility as this solution is already used in many places. So the proposition is not to change ClassA and ClassB logic that is already working, but add new interface implementation, that will cover this type-conditional logic you wanted to implement in your ABC method.
I would add another interface that holds method doing all the type-conditional logic and simply call it in the middle of your ABC class. In order to keep the constraints your generic type would need to implement both IDestination and IDestinationLogic interface. Of course the ABC method may need slight modifications but it's hard to say how precisely should it look like, given that we totally don't know anything about what it should do.
An example implementation could look like that:
public class GenericMethodClass
{
public string ABC<T>(T obj) where T : IDestination, IDestinationLogic
{
var result = string.Empty;
//some code happens here
var typeConditionalLogicResult = obj.DoSomething();
// do more stuff with according to the result of type-specific calculations
return result;
}
}
public class ClassA: IDestination, IDestinationLogic
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
public string DoSomething()
{
return Var2;
}
}
public class ClassB: IDestination, IDestinationLogic
{
public string Var1 { get; set; }
public string Var2 { get; set; }
public string Var3 { get; set; }
public string Var4 { get; set; }
public string Var5 { get; set; }
public string DoSomething()
{
return Var4;
}
}
public interface IDestination
{
string Var1 { get; set; }
string Var2 { get; set; }
}
public interface IDestinationLogic
{
string DoSomething();
}
The approach I suggested with interfaces is very similar to the template method design pattern, which initially included abstract classes. You can read about it here: http://www.dofactory.com/net/template-method-design-pattern maybe it will put more light on your case
you can use Reflection for getting these value like this:
public static string ABC<T>(T obj)
{
string s=string.Empty;
//Some code
if(obj is ClassA)
s = obj.GetType().GetProperty("Var2").GetValue(obj, null).ToString(); //of classA
if (obj is ClassB)
s = obj.GetType().GetProperty("Var4").GetValue(obj,null).ToString(); //of classB
//Some code
return s;
}
Related
I have the following scenario that involves a couple of interfaces as below
internal interface ITranslation
{
string LanguageCode { get; set; }
string Title { get; set; }
}
Any object that hold translations will implement the ITranslation interface. Some of these objects can have synonyms as well, so I have another interface
internal interface ITranslationWithSynonmys : ITranslation
{
IList<string> Synonyms { get; set; }
}
Next step I have defined ITranslatable<T> interface for any object that has translations and can be translated in different languages
internal interface ITranslatable<T> where T : ITranslation
{
IList<T> Translations { get; set; }
}
while when there are synonyms involved the ITranslatableWithSynonyms<T> looks like this
internal interface ITranslatableWithSynonyms<T> : ITranslatable<T> where T : ITranslationWithSynonmys
{
IList<T> SynonymTanslations { get; set; }
}
Concrete implementations of ITranslation and ITranslationWithSynonmys would be
internal class BaseTranslation : ITranslation
{
public string Title { get; set; }
public string LanguageCode { get; set; }
}
internal class BaseTranslationWithSynonmys : ITranslationWithSynonmys
{
public IList<string> Synonyms { get; set; }
public string LanguageCode { get; set; }
public string Title { get; set; }
}
while an entity that can be translated would be
internal class TranslatableEntity : ITranslatable<ITranslation>
{
public IList<ITranslation> Translations { get; set; }
}
and if it has synomys
internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>
{
public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
public IList<ITranslationWithSynonmys> Translations { get; set; }
}
Next, I'm creating a service that can translate any object that implements ITranslatable<T> and I have defined it as
internal class TranslationService
{
internal string Translate(ITranslatable<ITranslation> translatable, string languageCode)
{
// It will iterate through the Translations list to find the correct translation
return string.Empty;
}
}
Now, when I try to use the service, I'm writting
var translationService = new TranslationService();
var translatableEntity = new TranslatableEntity();
var translatableWithSynonymsEntity = new TranslatableWithSynonymsEntity();
string x = translationService.Translate(translatableEntity, "en");
string y = translationService.Translate(translatableWithSynonymsEntity, "en");
and here the last line translationService.Translate(translatableWithSynonymsEntity, "en") fails to compile with error CS1503: Argument 1: cannot convert from 'TestInheritance.TranslatableWithSynonymsEntity' to 'TestInheritance.ITranslatable<TestInheritance.ITranslation>'
It's true that TranslatableWithSynonymsEntity doesn't implement ITranslatable<ITranslation>, but it implements ITranslatableWithSynonyms<ITranslationWithSynonmys> with both ITranslatableWithSynonyms<T> inheriting from ITranslatable<T> and ITranslationWithSynonmys inheriting from ITranslation.
I can get the code to compile by having TranslatableWithSynonymsEntity implement both ITranslatableWithSynonyms<ITranslationWithSynonmys> and ITranslatable<ITranslation>, but that means managing two lists and it doesn't look clean.
internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>, ITranslatable<ITranslation>
{
public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
public IList<ITranslationWithSynonmys> Translations { get; set; }
IList<ITranslation> ITranslatable<ITranslation>.Translations { get; set; }
}
Is there a way to avoid this? Or am I taking a wrong approach?
Thank you
Generic parameters are invariant by default, in the method Translate you want the type to be <ITranslation>, so you must provide a type whose (or its parents') generic parameter is exactly <ITranslation>.
In your example you cannot simply mark the parameter as covariant because it contains a property has both getter and setter.
Since the problem is the generic parameter, to solve the problem, don't specify one, in fact you have already constrained the generic parameter.
interface ITranslatable<T> where T : ITranslation
The method (or the class) just need to be declared with the same constraint.
internal string Translate<T>(ITranslatable<T> translatable, string languageCode)
where T : ITranslation
I am having a problem. Lets see an example:
you got this interface which would be implemented by Employee.cs and Owener.cs:
public interface IEmployee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
}
public class Employee: IEmployee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
}
public class Owner: IEmployee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public string Status{ get; set; } <--- //problem string
}
Now when we are using Dependency Injection and it returns the object of employee or manager, thats where i run into problem.
public class EmployeeCheck{
private IEmployee empObj;
public EmployeeCheck(IEmployee _em)
{
empObj=_em
}
public void PrintCheck()
{
string str=_em.FirstName;
string str2=(Owner)_emp.Status <--- //problem...how do I access it?? It can't be accessed cause
//IEMployee doesn't have status field!
}
So basically if I use IEmployee as the interface , I can't access fields in new the Owner class, and if I do put them in interface, then Employee class which doesn't need to implement it, will be forced to implement something it doesn't need! And I do need IEmployee due to DI injection or other design pattern
OK, I can't use abstract class...so lets discuss more about the IStatus solution...so you are talking about writing code like this:
public interface IStatus:IEmployee
{
public string Title { get; set; }
}
public class Owner: IEmployee, IStatus
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public string Status{ get; set; } <--- //problem string
}
But how do I work it in Employee check class?
public class EmployeeCheck
{
private IEmployee empObj;
public EmployeeCheck(IEmployee _em, IStatus)
{
empObj=_em
}
}
The scenario that you're dealing with could be handled traditionally using IoC Containers like StructureMap or Unity by using something called Named Instances. These containers provide this kind of functionality out of the box.
The same can be achieved in .NET Core in multiple ways. One way is to use the extension method from IServiceCollection. The below snippet walks you through how this could be done in your scenario
// using Microsoft.Extensions.DependencyInjection
// Startup.cs - ConfigureServices()
services.AddTransient(serviceProvider =>
{
Func<string, IMyClass> func = key =>
{
switch (key)
{
case "MyClass":
return serviceProvider.GetService<MyClass>();
case "MyClass1":
return serviceProvider.GetService<MyClass2>();
default:
throw new KeyNotFoundException();
}
};
return func;
});
//Register your services here as usual
services.AddTransient<IMyClass, MyClass>();
services.AddTransient<IMyClass, MyClass2>();
You are essentially creating a factory here that is going to give out the dependency of the type that you need based on the key. The following snippet of code shows how this can be done within your controller.
// ctor of your controller
public MyController(Func<string, IMyClass> injector)
{
// key here could be 'MyClass' or 'MyClass2'
IMyClass service = injector("<key>");
}
Below is the structure of sample classes I have considered for the above sample
// implementation 1
public class MyClass : IMyClass
{
}
// implementation 2
public class MyClass2 : IMyClass
{
}
// interface
public interface IMyClass
{
}
There are also other ways to handle this. You can take a look at this answer for other approaches.
It depends on how you use or why you have to use dependency injection. I think that in these cases according to your example it is not so good to use it, since it is giving you complexity in something simple.
If you are going to perform an action with the Status value, you could segregate the interface by generating a new one. Like this.
public interface IStatus { string Status { get; set; } } and then you implement this interface just in Owner and in your constructor EmployeeCheck you inject IStatus.
But if it is not necessary why not IEmployee you do it as an abstract class.
public abstract class Employee
{
public string Name { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
}
public class Owner : Employee
{
public string Status { get; set; }
}
public class EmployeeCheck
{
public EmployeeCheck(Employee employee)
{
var owner = employee as Owner;
var statuts= owner.Status;
}
}
The first question you need to consider is: what is EmployeeCheck supposed to do when it is instantiated with an Employee (say) since it seems to require Status to print a check?
The whole idea behind interfaces is that they provide a contract for the operations that can be performed with an object. In this case, you are trying to do something (use Status) that is not specified in the contract so the type system is making it a little bit harder (forcing you to cast).
An option (as suggested by #Diegorincon) which avoids casting, is to create another interface (something like IHasStatus) which implements IEmployee and then change the type in EmployeeCheck (CheckPrinter maybe clearer?) to IEmployeeWithStatus.
interface IEmployee
{
string FirstName { get; }
string LastName { get; }
}
interface IEmployeeWithStatus:IEmployee
{
string Status { get; }
}
public class Owner : IEmployeeWithStatus
{
public string FirstName { get; }
public string LastName { get; }
public string Status { get; }
}
class EmployeeCheck
{
private readonly IEmployeeWithStatus _employeeWithStatus;
public EmployeeCheck(IEmployeeWithStatus employeeWithStatus)
{
_employeeWithStatus = employeeWithStatus;
}
void PrintCheck()
{
// no casting needed
Console.Write($"{_employeeWithStatus.FirstName} {_employeeWithStatus.LastName} {_employeeWithStatus.Status}");
}
}
If you are stuck using the signatures in your example, one option for writing the code is to write a switch statement using the type pattern:
switch (employee)
{
case Owner owner:
{
// you can use owner.Status here
Console.WriteLine(owner.Status);
}
break;
case Employee employee:
{
// hmm.., now what?!
}
break;
}
It's cleaner than having to cast all over the place but at the end of the day, it's just pushing the same problem around.
(In the Object Oriented paradigm, this situation comes up all the time where you have a object in hand with a more general type (something like Animal) but you find yourself wanting to do operations based on its specific type (something like Dog). Switching on type as the code above does is usually considered a code smell. With more details, I might be able to offer some other ideas)
Say I have the following classes:
public abstract class A
{
protected abstract ReturnA Foo();
public void UseFoo()
{
var foo = Foo();
if (foo != null)
{
//logic here
}
}
}
public class B : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnB instead.
}
}
public class C : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnC instead.
}
}
public class ReturnA
{
public int Id { get; set; }
public string Address { get; set; }
}
public class ReturnB
{
public string Id { get; set; }
public string PhoneNumber { get; set; }
}
public class ReturnC
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I know that C# does not support derived return types, but this is not what I need either.
Classes B and C are implementation specific and therefore their return types have nothing to do with eachother.
The reason why I would want to handle this, is because the method UseFoo in class A may have some generic checks and other generic logic, that has nothing to do with the returned object itself.
So I want to "outsource" only the code that is implementation specific and not have to instead make UseFoo abstract and have every implementation write the same generic code.
Is there any way to solve this at all?
EDIT: Neither ReturnC nor ReturnB are derived from ReturnA. Updated with examples.
[DataContract]
public class OrderSyncData : ISync
{
public OrderSyncData(Order o)
{
this.CurrentOrderStatus = o.DriverStatus;
this.StatusDescription = o.StatusDescription;
SyncTimestamp = o.SyncTimestamp; ????
}
[DataMember]
public string CurrentOrderStatus { get; set; }
[DataMember]
public string StatusDescription { get; set; }
[DataMember]// I don't think I need these any more
public bool IsCanceled { get; set; }
[DataMember]
public bool IsResolved { get; set; }
[DataMember]
public bool IsPendingResponse { get; set; }
DateTime ISync.SyncTimestamp { get; set; }
}
How to set the value of ISync.SyncTimestamp? I tried casting the "this." but it doesn't work
This should work:
((ISync)this).SyncTimestamp = o.SyncTimestamp;
Note the extra braces around (ISync)this.
You just need to cast this:
((ISync) this).SyncTimestamp = o.SyncTimestamp;
Or you could do it in two statements:
ISync sync = this;
sync.SyncTimestamp = o.SyncTimestamp;
Basically, the explicit interface implementation means that the property is only available when you're viewing this in the context of simply ISync, not the implementation class.
This is because you've implemented SyncTimestamp explicitly. Explicit implementations cannot be accessed from a class instance. Why? Because explicit implementation allows you to implement multiple interfaces with the same member name.
class Foo: IBar, IFoo
{
bool IBar.FooBar {get;set;}
bool IFoo.FooBar {get;set;}
}
Then writing this.FooBar refers to which implementation? So either you cast this to the desired interface explicitly, like other answers suggest, or you don't implement the SyncTimestamp explicitly, but do it implicitly: public DateTime SyncTimestamp { get; set; }.
Then this.SyncTimestamp will work.
In some locations of my program I need access to the concrete implementation of an object (Test) and in other locations I only need a read-only interface (ITest). This is to prevent an user from assuming that all properties are set and modifiable
For example if the user calls TestFactory.Search the returned collection will prevent them from modifying the property A and using CollectionB (it is not set inside the function). I would like to be able to use object initializers and keep the properties names the same. I have the following solution:
public interface IReadOnly
{
int Id{ get; }
string Name{ get; }
}
public class ClassA : IReadOnly
{
int Id{ get; internal set; }
string Name{ get; set; }
}
public interface ITest
{
int Id{ get; }
IReadOnly A { get; }
}
public class Test : ITest
{
private ClassA classA = new ClassA();
int Id{ get; internal set; }
IReadOnly ITest.A{ get{ return classA; } }
public ClassA A
{
get
{
return classA;
}
set
{
classA = value;
}
}
public IEnumerable<string> CollectionB {get;set;}
}
public static class TestFactory
{
IEnumerable<ITest> Search(){ /**/ }
Test Read(){ /**/ };
}
Is there a better way to solve this problem and is the abusing the concept of explicit interface implementation?
I would have your Test class implement both interfaces, IReadOnly and ITest. When you want to restrict setter access, cast to IReadOnly, otherwise, use ITest or the concrete Test.
Maybe create an abstract class instead and then subclass the full access and read only behavior?