界面铸造

Dr.*_*ail 7 c# interface

我有一些课程,我无法改变.他们有一个Prop3共同的属性:

public class c1
{
    public  string Prop1 { get; set; }
    public  string Prop2 { get; set; }
    public  string Prop3 { get; set; }
}

public class c2
{
    public  string Prop2 { get; set; }
    public  string Prop3 { get; set; }
}

public class c3
{
    public  string Prop5 { get; set; }
    public  string Prop3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在我想在不知道类型的情况下访问此属性.我想过使用一个接口:

public interface ic
{
    string Prop3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但是此代码抛出了无效的强制转换异常:

c1 c1o = new c1() { Prop3 = "test" };
string res = ((ic)c1o).Prop3;
Run Code Online (Sandbox Code Playgroud)

Jcl*_*Jcl 11

C#不支持编译时鸭子输入,所以如果你不能改变你的类型,那就没有运气了.

你可以使用dynamic它来访问你的属性,它允许运行时鸭子输入(但是没有编译时间检查,如果使用Visual Studio,你将失去智能感知):

c1 c1o = new c1() { Prop3 = "test" };
string res = ((dynamic)c1o).Prop3;
Run Code Online (Sandbox Code Playgroud)

或通过反思:

c1 c1o = new c1() { Prop3 = "test" };
string res = (string)c1o.GetType().GetProperty("Prop3").GetValue(c1o);
Run Code Online (Sandbox Code Playgroud)

由于没有编译时检查,因此如果传递没有的实例,则需要处理异常Prop3.

或者,如果类型未密封,您可以尝试实现自己的派生类型,您可以在其中指定接口:

public interface ic
{
   string Prop3 { get; set; }
}

public class c1d : c1, ic {}
public class c2d : c2, ic {}
public class c3d : c3, ic {}
Run Code Online (Sandbox Code Playgroud)

这就需要你控制实例的创建不过,情况将需要类型的c1d,c2d,c3d,将无法正常工作,如果你得到类型的对象c1,c2c3

您可以像@David指出的那样进行显式类型转换(这是一个聪明的技巧),但这意味着您将拥有对象的两个实例.对于像问题中提到的那样非常简单的情况,它可能会...如果您需要更高级的东西,那可能会非常棘手


Maa*_*ten 7

使用类似适配器的结构来封装转换逻辑.当然,这样做的缺点是你必须在c4弹出时修改类.

public class Adapter {
    public Adapter(object c) {
        if (!(c is c1 || c is c2 || c is c3))
            throw new NotSupportedException();
        _c = c;
    }

    private readonly object _c;

    public string Prop3 {
        get {
            if (_c is c1) return ((c1)_c).Prop3;
            if (_c is c2) return ((c2)_c).Prop3;
            if (_c is c3) return ((c3)_c).Prop3;
            throw new NotSupportedException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var c1o = new c1() { Prop3 = "test" };
var adapter1 = new Adapter(c1);
var res1 = adapter1.Prop3;

var c2o = new c2() { Prop3 = "test" };
var adapter2 = new Adapter(c2);
var res2 = adapter2.Prop3;
Run Code Online (Sandbox Code Playgroud)