-1

I have a instance method that creates a new instance of a class. I would like for this to be a class method. The problem is that I get an error when trying to call GetType() in the static method. Is it possible to convert this method to a static method ?

error

An object reference is required for the non-static field, method or property 'object.GetType()'.

Customer.New

    public object WithAttributes(ExpandoObject valueObject)
    {
        var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.GetSetMethod() != null);

        var self = Activator.CreateInstance(GetType());
        var values = (IDictionary<string, object>)valueObject;
        foreach (var property in properties)
        {
            if (values.Keys.Contains(property.Name))
            {
                var val = values[property.Name];
                property.SetValue(self, values[property.Name]);
            }
        }

        return self;
    }

BaseEntity.cs

public class BaseEntity
{
    public Int64 Id { get; set; }
    public DateTime AddedDate { get; set; }
    public DateTime ModifiedDate { get; set; }
    public string IPAddress { get; set; }


    public object WithAttributes(ExpandoObject valueObject)
    {
        // Same code as above
    }
}

Customer.cs

public class Customer : BaseEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string MobileNo { get; set; }
}

Desired Usage

dynamic attributes = new ExpandoObject();
attributes.FirstName = "James";
attributes.LastName = "Jones";
var customer = Customer.WithAttributes(attributes);
Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188
  • 2
    `typeof(ContainingClass)`... – CodeCaster Sep 05 '17 at 13:30
  • @CodeCaster I don't know the type of the containing class. The class I'm creating this in is an abstract base class. I want the type of the child class. – Antarr Byrd Sep 05 '17 at 13:34
  • Then read [ask], try to explain your entire scenario in the question body by [edit]ing it and show what you've tried. – CodeCaster Sep 05 '17 at 13:36
  • @CodeCaster I don't believe this is a duplicate. I tried the solution on the referred question. It give the the type of the base class, but as I stated above I want the type of the actual instantiated object. – Antarr Byrd Sep 05 '17 at 13:37
  • Again, that is not mentioned in your question. [Edit] it, but please just research first. Plenty of related questions show up for "C# get type in static method", "C# get type of caller", and so on. See also [How can I find the method that called the current method?](https://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method), [How the static class's static method will know the caller?](https://stackoverflow.com/questions/11594140/how-the-static-classs-static-method-will-know-the-caller), and so on. – CodeCaster Sep 05 '17 at 13:38
  • @ispiro You can't you `this` in a static method. – Antarr Byrd Sep 05 '17 at 13:39
  • @ispiro I want the make WithAttributes static. – Antarr Byrd Sep 05 '17 at 13:41
  • This is not an answer but it is a workaround - you can use generics - `public static T WithAttributes((ExpandoObject valueObject))` and inside you can use `typeof(T)`. – Zohar Peled Sep 06 '17 at 05:23

1 Answers1

1

Well, Unfortunately for you it is impossible to get the implementing type from the base abstract type's static method. According to reed copsey's answer here and to Jon Skeet's answer there. As you can see in Jon's answer, the c# compiler associate the static method to the type it was declared in, even if it was executed from a deriving type.

This means that your abstract class must be aware of the type that implements it, or at least this method must be aware of the type where it's called from.

One way to do it is to create the WithAttributes as a generic method:

public static T WithAttributes<T>((ExpandoObject valueObject)) where T: BaseEntity, new
{
    // Here you can use typeOf(T)
}

This have some advantages (for instance, you can simply write var self = new T() instead of using Activator.CreateInstance(), and you don't need to return an object but the actual type.

However, you can't force the code that's calling this method to pass the correct type - nothing is stopping you from doing something like this:

var customer = Customer.WithAttributes<SomeOtherBaseEntityDerivedClass>(attributes);

Rob Leclerc's answer here Is another attempt to solve this using generics, Only this is creating the entire abstract class as a generic class, so instead of public class BaseEntity you will have

public class BaseEntity<TChild>

and then you can use typeOf(TChild).
This has the same disadvantage as my suggestion (you can do public class Customer : BaseEntity<SomeOtherType> just as easily).

Daniel A. White Answered his own question by taking the type as a parameter to the static method in the abstract class:

public static object WithAttributes(Type type, ExpandoObject valueObject)

Again, it has the same drawbacks as using the generic approach, but it also have the drawbacks of your approach - it must return object and you must use Activator.CreateInstance.

To conclude - What you are asking for can't be done safely.
I will not recommend using any of these approaches for a public API, but If you know your team are the only programmers that will inherit the BaseEntity, I would probably go with the generic approach, as long as you make sure everybody knows the compiler can't protect them from using the wrong type parameter.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121