【问题标题】:How to Convert between Interface derived types?如何在接口派生类型之间进行转换?
【发布时间】:2011-01-18 17:11:08
【问题描述】:

这里最简单的就是我想做的:

interface InterfaceA
{
    string var1 { get; set; }
    string var2 { get; set; }
}

public class DerivedA : InterfaceA
{
    public string var1 { get; set; }
    public string var2 { get; set; }
}

public class DerivedB : InterfaceA
{
    public string var1 { get; set; }
    public string var2 { get; set; }
}

public class DoEverything
{
    InterfaceA A = new DerivedA();
    InterfaceA B = new DerivedB();

    A.var1 = "Test1";
    A.var2 = "Test2";

    B = ConvertObject<DerivedB>(A);

    write(B.var1 + ", " + B.var2);

    // This doesn't work, I would like it to though.
    public T ConvertObject<T>(object obj)
    {
        T result = (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });

        foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
        {
            if (propertyInfo.CanRead)
            {
                try
                {
                    object value = propertyInfo.GetValue(obj, null);
                    propertyInfo.SetValue(result, value, null);
                }
                catch { }
            }
        }

        return result;
    }
}

现在我必须手动转换对象中的每个属性,当添加新属性时,我必须记住使用转换方法并添加它。我更希望这是自动完成的。

任何帮助将不胜感激。

提前致谢

【问题讨论】:

    标签: c# derived-types


    【解决方案1】:

    您可以向 DerivedB 添加一个构造函数,该构造函数将 InterfaceA 作为参数。

    例如

    public class DerivedB : InterfaceA
    {
        public string var1 { get; set; }
        public string var2 { get; set; }
        public DerivedB(InterfaceA original)
        {
           var1 = original.var1;
           var2 = original.var2;
        }
    }
    

    那么你可以这样使用它:

    public class DoEverything
    {
        InterfaceA A = new DerivedA();
    
        A.var1 = "Test1";
        A.var2 = "Test2";
    
        InterfaceA B = new DerivedB(A);
        write(B.var1 + ", " + B.var2);
    }
    

    【讨论】:

    • 这仍然让我有责任用构造函数更新所有派生类来处理它,然后我仍然必须记住为每个派生类添加到构造函数中。
    • 您可以创建一个包含“Create”方法的抽象基类并调用它(从 DoEverything 或从构造函数)。在任何情况下,您只需要在可能的“转换为”类上创建构造函数,而不必在所有类中。
    • 如果有人无法帮助我采用更有效的方法,这可能是我必须采取的路线。不过我确实有问题
    • 这几乎是标准的 OO 方式。
    【解决方案2】:

    我想我不知道你在说什么。为什么不为 DerivedA 和 DerivedB 声明使用 InterfaceA 进行初始化的构造函数?它会更简单、更灵活,因为每个派生类型都将负责从接口类型初始化自己。您可以稍后添加更多实现该接口的类型,并且它们可以被其他类使用而无需任何进一步的更改。

    【讨论】:

    • 原因是我的业务层有一个通用的虚拟类,它只是获取和设置接口的每个属性。虽然业务层无法访问我的真实课程。我需要序列化真实类并将其发送到网络服务进行计算。我无法序列化接口并且我的原始类没有在我的业务层中实现,原因让我感到沮丧但我无法控制。所以我必须将我的原始类转换为我的虚拟类,然后进行序列化。添加一个采用 Interface 类型的构造函数并没有帮助,因为我可以很容易地......
    • 将类声明为 DerivedB B = new DerivedB() { blah = A.blah, etc... } 这仍然需要从 A 到 B 的手动翻译
    • 这仍然是一个简单的答案,因为您使用的是已知界面。在您的虚拟类中实现 FromA 和 ToA 方法,其中 eaxh 将 InterfaceA 作为单个参数。 FromA 从 arg 中获取属性值,ToA 则相反。如果你知道 InterfaceA 是什么,就不需要反思。
    • 另外,虽然反射很方便,但要付出一定的性能损失。您还可能会遇到您实际上不想被复制的只读属性和计算属性的问题。而且由于我们不知道序列化是如何完成的,因此可能存在一些问题。是的,手动更新内容很痛苦,但它也让您有机会确保它正确完成。而且大概界面并没有太大变化,是吗?
    【解决方案3】:

    您需要为两个派生类实现operator overloading

    【讨论】:

    • 谢谢,虽然每次我更改接口以包含更多属性时,这都需要修改一个方法。我真的很想把它变成一种一击必杀的方法,我可以将它用于所有接口的所有派生类。只要他们共享同一个祖先就是。显然我无法将 Cat 类转换为 Toaster 类。
    • @user580270:那么你应该使用反射,但它相当慢而且无论如何 - 一个坏主意
    • 如果我选择反射,我将如何实现?
    • @user580270:GetType() 之后的所有内容 - 都是反射
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2021-01-01
    相关资源
    最近更新 更多