寻找一种更优雅的方法来对类属性执行自定义get / set功能

时间:2017-09-29 05:15:11

标签: c#

我试图找到一种方法来改进我的一些代码。我使用第三方API,它有一个非常复杂的API请求对象(我称之为ScrewyAPIObject),其中有大量的重复。每次要设置特定属性时,都可能需要一页代码。所以我构建了一个库来提供一个简化的包装器来设置/获取它的属性(并处理一些值预处理)。

以下是关于其运作方式的精简视图:

public abstract class LessScrewyWrapper
{
    protected ScrewyAPIRequest _screwy = new ScrewyAPIRequest();

    public void Set(string value)
    {
        Set(_getPropertyName(), value);
    }

    public void Set(string property, string value)
    {
        // Preprocess value and set the appropriate property on _screwy. This part 
        // has tons of code, but we'll just say it looks like this:
        _screwy.Fields[property] = "[" + value + "]";
    }

    protected string _getPropertyName()
    {
        // This method looks at the Environment.StackTrace, finds the correct set_ or 
        // get_ method call and extracts the property name and returns it.
    }

    public string Get()
    {
        // Get the property name being access
        string property = _getPropertyName();

        // Search _screwy's structure for the value and return it. Again, tons of code,
        // so let's just say it looks like this:
        return _screwy.Fields[property];
    }

    public ScrewyAPIRequest GetRequest()
    {
      return _screwy;
    }
}

然后我有一个子类,代表一个特定类型的棘手的API请求(有多种类型都具有相同的结构,但设置不同)。我们只说这个有两个字符串属性,PropertyA和PropertyB:

public class SpecificScrewyAPIRequest : LessScrewyWrapper
{
  public string PropertyA
  {
    get { return Get(); }
    set { Set(value); }
  }
  public string PropertyB
  {
    get { return Get(); }
    set { Set(value); }
  }
}

现在,当我想使用这个库时,我可以这样做:

SpecificScrewyAPIRequest foo = new SpecificScrewyAPIRequest();
foo.PropertyA = "Hello";
foo.PropertyB = "World";
ScrewyAPIRequest request = foo.GetRequest();

这很好用,但是有不同种类的数据类型,包括在我的Set / Get方法中使用泛型,当你处理50个属性时它只会使子类显得有点笨拙和50个Get()和Set()调用。

我喜欢做的只是定义字段,如下所示:

public class SpecificScrewyAPIRequest : LessScrewyWrapper
{
  public string PropertyA;
  public string PropertyB;
}

这会使课程看起来更清洁。问题在于,无论何时访问和修改字段的值,我都不知道如何让.NET对我的自定义处理程序进行回调。

我发现有人在PHP中使用__set和__get魔术方法做了类似的事情(尽管他们不打算使用它们),但我在C#中找不到类似的东西。有什么想法吗?

编辑:我考虑过对我的类使用索引方法,然后将对象类型值转换为适当的类型,但是我更喜欢保留定义属性的方法特定类型。

2 个答案:

答案 0 :(得分:1)

也许在你的情况下DynamicObject是一个合适的选择:

public class ScrewyDynamicWrapper : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        // get your actual value based on the property name

        Console.WriteLine("Get Property: {0}", binder.Name);
        result = null;
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        // set your actual value based on the property name

        Console.WriteLine("Set Property: {0} # Value: {2}", binder.Name, value);
        return true;
    }
}

定义你的包装器对象:

public class ScrewyWrapper
{
    protected dynamic ActualWrapper = new ScrewyDynamicWrapper();

    public int? PropertyA
    {
        get { return ActualWrapper.PropertyA; }
        set { ActualWrapper.PropertyA = value; }
    }

    public string PropertyB
    {
        get { return ActualWrapper.PropertyB; }
        set { ActualWrapper.PropertyB = value; }
    }
}

但是,您不能依赖此ScrewyDynamicWrapper中的属性类型,因此这取决于您的实际API要求 - 可能对您不起作用。

答案 1 :(得分:1)

而不是字段,如果在类中定义为属性,那将更容易。

classdef test_parser < matlab.mixin.Copyable & dynamicprops
    properties (AbortSet = true)
        a       
    end
end

function result = make_class(array)
    result = test_parser;
    result.a = array(1);
    if length(array)>1
        result.addprop('b')
        result.b=array(2);
    end
end

>> make_class([10])
ans = 
  test_parser with properties:

    a: 10
>> make_class([10,20])
ans = 
  test_parser with properties:

    a: 10
    b: 20

然后,您可以创建扩展通用方法以返回public class SpecificScrewyAPIRequest { public string PropertyA { get; set; } public string PropertyB { get; set; } } 对象。

ScrewyAPIRequest

现在,您可以轻松地从任何类对象中获取public static class Extensions { public static ScrewyAPIRequest GetRequest<T>(this T obj) { ScrewyAPIRequest _screwy = new ScrewyAPIRequest(); var test= obj.GetType().GetProperties(); foreach (var prop in obj.GetType().GetProperties()) { _screwy.Fields[prop.Name] = prop.GetValue(obj, null); } return _screwy; } }

您的代码如下所示。

ScrewyAPIRequest