Configure StatePrinter to only follow the declared types?

烂漫一生 提交于 2019-12-13 19:34:46

问题


I'm using Stateprinter to print/compare my types. It works quite nicely, however, it does compare the actual type of each (sub) object instead of the declared type of the subobject.

An example:

class X {
  string Foo;
  int Bar;
}

interface IMyData {
  public X MyConfig { get; }
}

Now, when calling:

var cfg = ConfigurationHelper.GetStandardConfiguration();
cfg.Add(new PublicFieldsAndPropertiesHarvester());
var printer = new Stateprinter(cfg);

// ...

IMyData v = new MyDataWithMoreStuff();

printer.PrintObject(v);

This will print all the public fields and properties of MyDataWithMoreStuff instead of only the public state visible via IMyData.

Is there a way to do this with Stateprinter, or if that is currently not implemented, is it even possible using C# reflection to walk the "member tree" of an arbitrary object and treat the fields not by the concrete types that they have at runtime, but by the (base / interface) types the variables are declared with?


回答1:


As of v2.1.xx you can now specify projections of types based on other types. Ie. do the following

    [Test]
    public void TestIncludeByType()
    {
        var sut = new AtoD();
        Asserter assert;

        assert = TestHelper.CreateShortAsserter();
        assert.PrintEquals("new AtoD() { A = 1 B = 2 C = 3 D = 4 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.IncludeByType<AtoD, IA>();
        assert.PrintEquals("new AtoD() { A = 1 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.IncludeByType<AtoD, IA, IB>();
        assert.PrintEquals("new AtoD() { A = 1 B = 2 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.IncludeByType<AtoD, IA, IB, IC>();
        assert.PrintEquals("new AtoD() { A = 1 B = 2 C = 3 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.IncludeByType<AtoD, IA, IB, IC, ID>();
        assert.PrintEquals("new AtoD() { A = 1 B = 2 C = 3 D = 4 }", sut);
    }

    [Test]
    public void TestExcludeByType()
    {
        var sut = new AtoD();
        Asserter assert;

        assert = TestHelper.CreateShortAsserter();
        assert.PrintEquals("new AtoD() { A = 1 B = 2 C = 3 D = 4 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.ExcludeByType<AtoD, IA>();
        assert.PrintEquals("new AtoD() { B = 2 C = 3 D = 4 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.ExcludeByType<AtoD, IA, IB>();
        assert.PrintEquals("new AtoD() { C = 3 D = 4 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.ExcludeByType<AtoD, IA, IB, IC>();
        assert.PrintEquals("new AtoD() { D = 4 }", sut);

        assert = TestHelper.CreateShortAsserter();
        assert.Project.ExcludeByType<AtoD, IA, IB, IC, ID>();
        assert.PrintEquals("new AtoD() { }", sut);
    }

but this is filtering based on types, not a general harvesting of state based upon reference types. That, I don't think it is possible the way the code is now:

 class IntroSpector  
 {
    void Introspect(object source, Field field)
    {
        if (IntrospectNullValue(source, field))
            return;

        var sourceType = source.GetType();

        ...

so StatePrinter asks for the underlying type (GetType()). You probably need to overload the method or maybe better, code a ReferenceAwareIntrospector which takes a third parameter, the reference parameter, and works with that.

It should be fairly easy to do this and making the introspector configurable is likewise an easy extension of the Configuration class.



来源:https://stackoverflow.com/questions/29697451/configure-stateprinter-to-only-follow-the-declared-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!