2

I tried to search for solutions, but my problem is I don't even know what terms to use. Generics, Delegates, LINQ, Reflection, and Abstract ideas could be part of the solution, but my "Google-fu" isn't turning up the right answer.

Question: I have multiple classes (ClassA, ClassB, ClassC) that all have the same 2-3 properties DoThisA, DoThisB, DoThisC.

The way the code works is that I always want to do the same code to set DoThisA, DoThisB, and DoThisC when I process each of the classes.

For example, to simplify, the logic will always be:

{some computations to set string currentValueImProcessing to something}
if (xyz) [ClassA|B|C].DoThisA = currentValueImProcessing
else [ClassA|B|C].DoThisB = currentValueImProcessing

I don't want to write those same statements over and over, so how do I just send a reference to the class (A,B,C) to a method to do the logic?

If it was written correctly each of ClassA, ClassB, and ClassC would have implemented some generic class and I could use that, but I cannot. Each of the classes are independent but have the same named properties.

Any guidance on concepts/code?

Thanks!

2
  • sounds like the classes are a given, he cant change them Commented Oct 29, 2014 at 23:18
  • I'll add some clarification. The classes were dynamically generated from XSD.exe. There's a very large set of XSD that I am attempting to fill a compliant XML document with. Using XSD.exe turned everything into classes that I can easily reference. I would like to make it so if I had to re-run XSD.exe (for a new version) I wouldn't have to go back in and re-edit (to use interfaces) the dynamically created file from XSE.exe Commented Oct 30, 2014 at 13:47

5 Answers 5

4

Create an interface for your properties:

internal interface IDoThis
{
    public string DoThisA { get; set; }
    public string DoThisB { get; set; }
    public string DoThisC { get; set; }
}

Then, make your classes implement it:

public class ClassA : IDoThis
{
    public string DoThisA { get; set; }
    public string DoThisB { get; set; }
    public string DoThisC { get; set; }
}

public class ClassB : IDoThis
{
    // Same properties
}

public class ClassC : IDoThis
{
    // Same properties
}

This, way, you'll be able to create a static initializer method somewhere:

internal static class MyClassesExtensions
{
    public static void InitTheStuff(this IDoThis obj)
    {
        // Do something here, for example:
        if (String.IsNullOrEmpty(obj.DoThisA))
            obj.DoThisA = "foo";
        else
            obj.DoThisB = obj.DoThisC;
    }
}

And then you can just call this.InitTheStuff() anywhere from ClassA, ClassB and ClassC.

Sign up to request clarification or add additional context in comments.

4 Comments

Lucas, thank you, however the part that fails my requirements above is the ClassA : IDoThis part. The thing is there are many of these classes automatically created by XSD.EXE and I would have to manually alter all of them. While it is how you do this type of thing, it's not what I was looking for above. Thanks though!
BTW I don't want to offend anyone, but can I down vote this since it wasn't what I was looking for? That is, I knew this solution, but was looking for a way around not using interfaces.
@Adam OK no problem, I thought you'd be able to use this solution. As for the downvote, you can't downvote yet because you have not enough reputation, but you can mark the most helpful answer as accepted, and it will be prominently displayed at the first place. Another point is: you generally should only downvote answers which have problems, or those that you disagree with, not the answers which are correct (hopefully mine is) but that you didn't/couldn't use. But in the end voting is up to you, so if you really feel you should downvote this, come back later when you'll have enough reputation.
thanks for the how-to! I've been using the site for ideas but never actually dove into using it. I'm not down-voting.
3

you can either use reflection or you can use dynamic (dynamic will use reflection for you)

dynamic obj = new ClassA();
obj.DoTHisA();

is how to do it with dynamic

I am assuming that you are talking about classes that you intend to instantiate. If DoThisA,B,C are static methods then you must use reflection

NOTE - if you can change the classes then add an interface as others have suggested, or even a common base class

The reflection one looks like this

var type = obj.GetType(); // obj is ClassX object
var method = type.GetMethod("DoTHisA");
method.Invoke(obj);

I have not checked this - so the syntax might be a bit off - but this is the basic mechanics of reflection method calling. YOu need to get fancier if there are multiple methods with the same name, if the methods takses params etc

5 Comments

I'd only resort to late-binding if there was no alternative. If you're designing these classes yourself and have the option to implement a common interface then that would be a preferable solution.
i agree - my reading of the last paragraph is that the classes are a given - he cant change them
this one is I guess most suitable one , by the way which c# version needed to compile dynamic ?
Thank you! I didn't come across "dynamic" in my search. I'm curious what the pure reflection solution would look like. To google I go...BTW it appears Visual C# 2010 includes dynamic: msdn.microsoft.com/en-us/library/dd264736.aspx
+1 for dynamic, it's easier and more readable than reflection anyway.
2

There are at least four options open to you - maybe more.

  1. Create an interface, which is implemented by all of your classes and that includes the common methods.
  2. Create a base class from which all classes inherit. The common functionality can then be implemented in the base class. If the implementation differs depending on the clases, but you can define common signatures for the methods, make your base class an the common funtionality abstract. You then can implement the actual functionality in each of your classes.
  3. Use a dynamic object as in @pm100's solution.
  4. Use reflection to access the common functionality.

As a guidance methods 1. and 2. are to be preferred, as they allow your code to be checked on compile time. If, however, you do not have control over the classes that contain the common functionality - for example you do not have access to the source code or you are permitted to make changes to the code - you can use the other two methods.

If you'd ask me which of the two I would prefer, I guess that I would go for 3. over 4. But this is personal preference.

6 Comments

Great summary of the options. While 1 & 2 aren't unachievable (I do have access to the code) it is a bit of work to identify and re-code all the classes. Still a possibility if 3 & 4 aren't great solutions. I am curious how reflection would look however.
@LucasTrzesniewski: I said 'at least', didn't I ... :-))
@Adam: I'll elaborate if I find the time today or tomorrow.
@Axel true... but I added this method as another answer anyway since it was missing ;)
@Axel Is the reflectionis similar to (given mClassA is instantiated from Class A): var obj = mClassA.GetType(); PropertyInfo aProp = obj.GetProperty("DoThisA"); PropertyInfo bProb = obj.GetProperty("DoThisB"); aProp.SetValue(obj, "Foo"); bProp.SetValue(obj, "42"); Does that seem correct?
|
1

Prob you are talking about inheritance.

For your task you need a base abstract class with general properties:

public abstract class Base
{
    public bool DoThisA { get; set; }

    public bool DoThisB { get; set; }
}

and child classes:

public class A : Base { }
public class B : Base { }
public class C : Base { }

After that you can create a method which will accept object of type Base

public void Do(Base b, bool xyz, bool currentValueImProcessing)
{
    if (xyz)
    {
        b.DoThisA  = currentValueImProcessing;
    }
    else
    {
        b.DoThisB  = currentValueImProcessing;
    }
}

1 Comment

Kirill, please see my comments above for Lucas's response. This is the easy way, but not what I wanted to do per my requirments.
0

There are already many methods provided here, so just for the sake of completeness... Here's some runtime code generation:

public class ClassA
{
    public string DoThisA { get; set; }
    public int DoThisB { get; set; }
    public bool DoThisC { get; set; }

    public void Init()
    {
        // You can call this from anywhere, even from an unrelated class
        MyClassInitializer<ClassA>.Init(this);
    }
}

public static class MyClassInitializer<T>
{
    // Create the getters/setters you need, and make sure they're static.

    private static readonly Func<T, string> _getA = BuildGetter<string>("DoThisA");
    private static readonly Action<T, string> _setA = BuildSetter<string>("DoThisA");

    private static readonly Func<T, int> _getB = BuildGetter<int>("DoThisB");
    private static readonly Action<T, int> _setB = BuildSetter<int>("DoThisB");

    private static readonly Func<T, bool> _getC = BuildGetter<bool>("DoThisC");
    private static readonly Action<T, bool> _setC = BuildSetter<bool>("DoThisC");

    private static Func<T, TValue> BuildGetter<TValue>(string name)
    {
        var obj = Expression.Parameter(typeof(T));
        return Expression.Lambda<Func<T, TValue>>(Expression.Property(obj, name), obj).Compile();
    }

    private static Action<T, TValue> BuildSetter<TValue>(string name)
    {
        var obj = Expression.Parameter(typeof(T));
        var value = Expression.Parameter(typeof(TValue));
        return Expression.Lambda<Action<T, TValue>>(Expression.Assign(Expression.Property(obj, name), value), obj, value).Compile();
    }

    public static void Init(T obj)
    {
        // Here's your custom initialization method

        if (_getA(obj) == "Foo")
            _setB(obj, 42);
        else
            _setC(obj, true);
    }
}

Not necessarily the easiest one to grasp, but this should be much faster than using dynamic or reflection. That said, if you don't need the speed, stick with dynamic as it's easier.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.