首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >界面铸造

界面铸造
EN

Stack Overflow用户
提问于 2016-08-19 11:57:21
回答 5查看 190关注 0票数 7

我有几门课我不能改。它们有一个共同的属性Prop3

代码语言:javascript
复制
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; }
}

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

代码语言:javascript
复制
public interface ic
{
    string Prop3 { get; set; }
}

但是,此代码引发无效的强制转换异常:

代码语言:javascript
复制
c1 c1o = new c1() { Prop3 = "test" };
string res = ((ic)c1o).Prop3;
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2016-08-19 12:00:19

C#不支持编译时duck-typing,所以如果您不能更改您的类型,那就没有希望了。

您可以使用dynamic访问您的属性,这允许运行时鸭子类型(但不需要编译时检查,如果使用Visual,则会失去智能感知):

代码语言:javascript
复制
c1 c1o = new c1() { Prop3 = "test" };
string res = ((dynamic)c1o).Prop3;

或通过反射:

代码语言:javascript
复制
c1 c1o = new c1() { Prop3 = "test" };
string res = (string)c1o.GetType().GetProperty("Prop3").GetValue(c1o);

由于没有编译时检查,所以您需要处理异常,以防您传递一个没有Prop3的实例。

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

代码语言:javascript
复制
public interface ic
{
   string Prop3 { get; set; }
}

public class c1d : c1, ic {}
public class c2d : c2, ic {}
public class c3d : c3, ic {}

这将要求您控制实例的创建,但是,实例需要类型为c1dc2dc3d,如果您获得c1c2c3类型的对象,则无法工作。

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

票数 11
EN

Stack Overflow用户

发布于 2016-08-19 12:15:04

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

代码语言:javascript
复制
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();
        }
    }
}

用法:

代码语言:javascript
复制
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;
票数 7
EN

Stack Overflow用户

发布于 2016-08-19 12:43:35

另一种方法是使用反射获取具有指定名称的属性的值。

例如,编写如下简单的助手方法:

代码语言:javascript
复制
public static T GetProperty<T>(object obj, string name)
{
    return (T) obj.GetType().GetProperty(name).GetValue(obj);
}

然后给出以下不相关的类:

代码语言:javascript
复制
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; }
}

public class C4
{
    public string Prop4 { get; set; }
    public string Prop5 { get; set; }
}

您可以像这样访问Prop3属性:

代码语言:javascript
复制
object c1 = new C1 {Prop3 = "C1"};
object c2 = new C2 {Prop3 = "C2"};
object c3 = new C3 {Prop3 = "C3"};
object c4 = new C4();

Console.WriteLine(GetProperty<string>(c1, "Prop3")); //Prints C1
Console.WriteLine(GetProperty<string>(c2, "Prop3")); //Prints C2
Console.WriteLine(GetProperty<string>(c3, "Prop3")); //Prints C3
Console.WriteLine(GetProperty<string>(c4, "Prop3")); // Throws an exception.
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39038536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档