So, I have a little bit of an issue that I can't exactly wrap my head around.
So, I have a base class called Property, and I have a lot of classes that derive from that one, like IntProperty, ColorProperty and so on. Now, I also have a few of them that are of the enum type and currently they are all separate classes. I'd like to make it a generic class but here's the issue with this:
In a different part of the code I need to handle all of them. Keep in mind I can't use virtual functions for this (I'm doing something with the UnityEditor).
Currently, I have a function that takes a Property as a parameter and then I do this for all types that derive from Property:
if(property is IntProperty)
{
IntProperty intProperty = property as IntProperty;
intProperty.theValue = specific_int_function();
}
That specific_int_function is the same for all enum values privided I have the T from a generic.
Ideally I'd like to do something like this (pseud-ish code):
(using T)
{
if(property is EnumProperty<T>)
{
EnumProperty<T> enumProperty = property as EnumProperty<T>;
enumProperty.value = (T)my_enum_value_function(typeof(T));
}
}
Any idea about how I could make all this code nicer?
Hopefully I provided all the relevant information.
Edit:
It's not so much that I can't use virtual functions in those classes but I can't call any of the specific functions in that particular file. I have 2 compilation groups and only one can access those functions (EditorGUI functions for people who know what I'm talking about)
Regards,
Lorin
Keep in mind I can't use virtual functions for this (I'm doing something with the UnityEditor).
That's really what you should be doing. If you can't, then fine, but I'm leaving this note here for the benefit of other people will be reading this question and answer too.
In my experience, the least difficult way of achieving this is with a helper class, because it lets you avoid some of the reflection complexity that you would have to deal with if you used a generic helper method.
abstract class EnumPropertyHelper {
public abstract void DoSomething(Property property);
}
class EnumPropertyHelper<T> : EnumPropertyHelper {
public override void DoSomething(Property property) {
EnumProperty<T> enumProperty = property as EnumProperty<T>;
enumProperty.value = (T)my_enum_value_function(typeof(T));
}
}
Then,
if (property.GetType().IsGenericType
&& property.GetType().GetGenericTypeDefinition() == typeof(EnumProperty<>)) {
var helperType = typeof(EnumPropertyHelper<>).MakeGenericType(property.GetType().GetGenericTypeArguments());
var helper = (EnumPropertyHelper)Activator.CreateInstance(helper);
helper.DoSomething(property);
}
But you do need to jump through hoops similar to this one whatever you end up doing, because C# and .NET don't allow you to have generic code in non-generic methods.
You could use add a function pointer to the class, and each constructor could implement it's own function?
Add a property Func<void> functionPTR = null
In each class you'd have a function such as
void specific_int_function() {
//Do Something
}
In the class constructor
functionPTR = specific_int_function;
And then in the generic class
void GenericHandler() {
functionPTR();
}
I'm not sure about the syntax, but this should give you the performance you're going for.
Read up on function pointers to see how to define the return value and function parameters.
Related
I'm currently working on writing a method that, for the sake of this problem, generates mazes.
Here's the (simplified) version of the classes involved:
public interface IAlgorithm<out MazeType> where MazeType : Maze
{
MazeType GoGenerate();
}
public class AlgorithmBacktrack : IAlgorithm<Maze>
{
public Maze GoGenerate()
{
//Do things
return new Maze();
}
}
public class Maze
{
}
public class MazeWithPath : Maze
{
}
What I'd like to do now is create helper to call this Algorithm:
public class MazeGenerator
{
public static MAZETYPEGENERIC Generate<AlgorithmType>()
where AlgorithmType : IAlgorithm<MAZETYPEGENERIC>, new()
{
var alg = new AlgorithmType();
return alg.GoGenerate();
}
}
The thing that I can't get to work though is the MAZETYPEGENERIC. Theoretically C# could know that whatever interface implementation of IAlgorithm I put in there would have the MAZETYPEGENERIC configured. However C# still want's me to add that as a Generic parameter to the method. E.g.:
public static MAZETYPEGENERIC Generate<AlgorithmType, MAZETYPEGENERIC>()
where AlgorithmType : IAlgorithm<MAZETYPEGENERIC>, new()
...
This however would mean that the invocation of this call would also require this parameter. Even though it could theoretically be inferred from the AlgorithmType.
//Ideal way to call this method:
Maze m = MazeGenerator.Generate<AlgorithmBacktrack>();
//Actual way to call this after adding the additional generic parameter:
Maze m = MazeGenerator.Generate<AlgorithmBacktrack, Maze>();
I would love to see/hear if someone has an idea on how to accomplish option 1 (the ideal way of doing this).
One way to do this is to accept an instance of IAlgorithm<MAZETYPEGENERIC>, and let type inference infer the type parameter MAZETYPEGENERIC . Now you wouldn't need the AlgorithmType type parameter
Maze m = MazeGenerator.Generate(new AlgorithmBacktrack());
...
public static MAZETYPEGENERIC Generate<MAZETYPEGENERIC>(IAlgorithm<MAZETYPEGENERIC> algorithm)
where MAZETYPEGENERIC : Maze {
return algorithm.GoGenerate();
}
You would have been able to access the type parameter of IAlgorithm if C# interfaces used associated types (like Swift), rather than generics. So it's not like this is completely impossible feature to have in a language. For a comparison see this post.
If "instantiate the Algorithm class" is all you need, the closest I can get is probably by moving the call to GoGenerate method out of Generate method, like this:
static T Generate<T>() where T : IAlgorithm<Maze>, new()
{
return new T();
}
Maze m = MazeGenerator.Generate<AlgorithmBacktrack>().GoGenerate();
// I made the algorithm class up
MazeWithPath m = MazeGenerator.Generate<AlgorithmBacktrack2>().GoGenerate();
Or if the type of local variable m is always Maze, you could also do something like:
static Maze Generate<T>() where T : IAlgorithm<Maze>, new()
{
return new T().GoGenerate();
}
Also want to comment on
Theoretically C# could know that whatever interface implementation of IAlgorithm I put in there
I hope C# would not (like it currently does). T in your case is covariant. If T is implementation of IAlgorithm<MazeWithPath>, both Maze, MazeWithPath and object are semantically correct for return type.
The compiler can't choose one without knowing the context of your code. And if it can, it may choose a wrong one for you:
// This is only correct when the compiler chooses MazeWithPath as return type
// It will become invalid if compiler chooses Maze or object
MazeWithPath m = Generate<AlgorithmBacktrack2>();
In saying that, making Generate method to take two generic parameters might make more sense IMO.
Is it possible to call a method in implementation class of an interface which is not defined in interface using interface variable like below:
interface ILookup {
public void someInterfaceMethod1();
public void someInterfaceMethod2();
}
...and implementation class:
public class extendedLookUpImplementor: ILookup
{
//constructor
LookUpImplementor(){
}
public void someInterfaceMethod1(){
// Implementation Code here.
}
public void someInterfaceMethod2(){
// Implementation Code here.
}
public void ExtendedMethod(){
// Implementation Code here.
}
}
In client code:
ILookup lookupVar = new LookUpImplementor();
lookupVar -> someInterfaceMethod1(); // i know it will work.
lookupVar -> someInterfaceMethod2(); // i know it will work.
My question is, can i call ExtendedMethod using lookupVar like below:
lookupVar -> ExtendedMethod(); // Note again that ExtendedMethod() is not defined in Ilookup interface/contract.
Only by casting lookupVar as extendedLookUpImplementor, or by reflection I think.
First of all as Ian1971 said, yes you can by casting it to specific type, say
ILookup lookupVar = new LookUpImplementor();
((extendedLookUpImplementor)lookupVar).ExtendedMethod(); //this should work
or alternatively using dynamic/reflection.
Having said that, I really really don't think this is a good way to do this because it would violate one of the objective of contract/interface.
For instance, if we have ILookup variable "lookupVar"
dynamic lookup = lookupVar;
lookup.ExtendedMethod(); //this would work
At any point in time, the code utilizing the object lookupVar does not guarantee that there would be a method ExtendedMethod and can throw on Exception on run time.
My real question to you would be, why you want to add a method that cannot be added in contract, what is your objective here. If the method is extending the class, try going through C# extension method as they might fit in your scenario.
I have a similar problem and tried to depict it with code as it is easier to explain.
Basically I have a generic collection, so irrespective of which type of collection its instantiated as, it will have some common properties and events. And I am interested in these common properties.
Say, I have the instantiated obect of the generic collection - what is the best way to get these properties and subscribe to the events? I understand I can do it by implementing an interface and casting it to the interface definition but I don't like doing that as I am just doing it to please a single requirement. Is there a better way to refactor this?
public interface IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod
{
string Detail { get; }
event Action<bool> MyEvent;
}
public class MyList<T> : List<T>
//, IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod
{
public string Detail
{
get;
}
}
class Program
{
static void Main(string[] args)
{
MyList<int> mi = new MyList<int>();
MyList<string> ms = new MyList<string>();
MyList<char> mc = new MyList<char>();
GetDetail(mi);
GetDetail(ms);
GetDetail(mc);
}
//please note that obect need not be mylist<t>
static string DoSomeWork(Object object)
{
//Problem: I know myListObect is generic mylist
//but i dont know which type of collection it is
//and in fact i do not care
//all i want is get the detail information
//what is the best way to solve it
//i know one way to solve is implement an interface and case it to get details
var foo = myListObject as IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod;
if (foo != null)
{
//is there another way?
//here i also need to subsribe to the event as well?
return foo.Detail;
}
return null;
}
}
You can make your method generic:
static string GetDetail<T>(MyList<T> myList)
{
return myList.Detail;
}
This will allow you to call it with the same code you already have written, and completely eliminate the interface.
Edit in response to comments:
Given that you don't know the type, and you're just checking against an object, it does seem like an interface is the best approach here. Providing a common interface allows you to expose all of the members you need regardless of what's contained within the collection, which provides the correct behavior.
Make your GetDetail method generic:
static string GetDetail<T>(MyList<T> list)
{
return list.Detail;
}
EDIT: I've assumed that there are potentially multiple collection classes involved. If there's actually only one class - MyList<T> - then using a generic method is absolutely the right way to go.
i understand i can do it by implementating an interface and casting it to the interface defenition but i dont like it as i am just doing it to please one single requirement.
You're doing it to express what the collections have in common. Unless the common members are implementing an interface, they just happen to have the same name - the interface shows that they have the same intended meaning too.
Using an interface is the right way to go here - but it's not clear why your GetDetail method doesn't just take the interface as a parameter... assuming you need the method at all.
public class BusinessObjects<O>
where O : BusinessObject
{
void SomeMethod()
{
var s = O.MyStaticMethod(); // <- How to do this?
}
}
public class BusinessObject
{
public static string MyStaticMethod()
{
return "blah";
}
}
Is there a correct object oriented approach to accomplishing this or will I need to resort to reflection?
EDIT: I went too far in trying to oversimplify this for the question and left out an important point. MyStaticMethod uses reflection and needs the derived type to return the correct results. However, I just realized another flaw in my design which is that I can't have a static virtual method and I think that's what I would need.
Looks like I need to find another approach to this problem altogether.
You can't access a static method through a generic type parameter even if it's constrained to a type. Just use the constrained class directly
var s = BusinessObject.MyStaticMethod();
Note: If you're looking to call the static method based on the instantiated type of O that's not possible without reflection. Generics in .Net statically bind to methods at compile time (unlike say C++ which binds at instantiation time). Since there is no way to bind statically to a static method on the instantiated type, this is just not possible. Virtual methods are a bit different because you can statically bind to a virtual method and then let dynamic dispatch call the correct method on the instantiated type.
The reason you can't reference the static member like this:
O.MyStaticMethod();
Is because you don't know what type O is. Yes, it inherits from BusinessObject, but static members are not inherited between types, so you can only reference MyStaticMethod from BusinessObject.
If you are forcing O to inherit from BusinessObject, why not just call it like this:
void SomeMethod()
{
var s = BusinessObject.MyStaticMethod(); // <- How to do this?
}
public static FirstObjectType GetObject(SecondObjectType secondobjectType)
{
do something
}
Where should I put this function? Should I put it in SecondObjectType class or FirstObjectType class in terms of code readability, customs and traditions? Should the function be included in the return class or the parameter class from your experience?
Thanks for your answer.
I usually put the method in the class that has the same type as the return type of the method.
eg:
public static FirstObjectType GetObject(SecondObjectType secondobjectType)
{
do something
}
would go in the FirstObjectType class.
Alternatively you can use the Factory Pattern and have a factory for getting the objects you need. Which could give you code simliar to the following:
FirstObjectTypeFactory.GetObject(SecondObjectType secondObjectType)
Then you always know which factory to get the object from based on its return type.
This is way to vague to answer, but I'll give a few general tips
If you have a collection of FirstObjectTypes and are trying to find the one that matches SecondObjectType, then it belongs to the class that owns the collection. This could be a factory pattern.
If you are always creating a new FirstObjectType, it could just be a constructor for FirstObjectType.
Does SecondObjectType have to have knowledge of FirstObjectType? If so, then it I would consider making it a method on SecondObjectType.
There are a million other scenarios and there is no one size fits all.
I'll create an Extension Method for that.
Just add this in the signature
public static FirstObjectType GetObject(this SecondObjectType secondobjectType)
{
//do something
}
After that you can do:
SecondObjectType sobj = new SecondObjectType()
//code
FirstObjectType fobj = sobj.GetObject();
And put it with my other extension method file like ExtensionMethods.cs.
Or if the class containing the GetObject method is static too, put it in the same class (In this case in the SecondObjectType's class)