C#:派生类上具有不同返回类型的属性

发布于 2024-12-15 01:58:28 字数 1334 浏览 1 评论 0原文

我试图寻找这个问题的答案,但找不到太多,很可能是因为我不知道如何正确寻找它,所以就在这里。非常感谢所有帮助。

基类看起来像

abstract public class Property
{
    private String name;

    public Property(String propertyName)
    { 
        name = propertyName; 
    }

    public String Name
    {
        get { return name; }
    }

    abstract public override String ToString();
}

派生类看起来像

public class StringProperty : Property
{
    private String value; // different properties for different types

    public StringProperty(String propertyName, String value) : base(propertyName)
    {
        this.value = value;
    }

    public String Value // different signature for different properties
    {
        get { return value; }
    }

    public override String ToString()
    {
        return base.Name + ": " + value;
    }
}

在运行时,该函数接收“Property”对象的集合。我需要做什么才能获得每个的“值”?我是否需要一个大的 if 语句来查询每个“Property”对象的类型?如果没有,是否有更优雅的解决方案?

我尝试定义一个要覆盖的抽象“Value”属性,但由于返回类型不同,因此它不起作用。我还尝试使用阴影“Value”属性,但我无法使其工作。使用类 COM 变体的想法听起来也不太合适。

预先非常感谢。

编辑:

我应该添加关于我想要做什么的详细信息。这些属性显示在 Winforms 应用程序中。不同的“TextBox”代表不同的属性,并被过滤以获取正确的输入(取决于类型)。更新的值被读回并存储。容器对象将被序列化为 JSON 并在 Android 和 iPhone 客户端上反序列化,最终这些值将被传递到运行本机 C++ 代码执行 OpenGL 操作的层中。我事先并不知道所有所需属性的类型,因此作为中间人,我希望使我的代码尽可能健壮,同时能够为 OpenGL 引擎提供支持。

I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.

With the base class that looks like

abstract public class Property
{
    private String name;

    public Property(String propertyName)
    { 
        name = propertyName; 
    }

    public String Name
    {
        get { return name; }
    }

    abstract public override String ToString();
}

And derived classes that look like

public class StringProperty : Property
{
    private String value; // different properties for different types

    public StringProperty(String propertyName, String value) : base(propertyName)
    {
        this.value = value;
    }

    public String Value // different signature for different properties
    {
        get { return value; }
    }

    public override String ToString()
    {
        return base.Name + ": " + value;
    }
}

During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?

I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.

Thanks a lot in advance.

EDIT:

I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青丝拂面 2024-12-22 01:58:28

您可以使用泛型类:

public class AnyProperty<T> : Property
{
    private T value;
    // ... etc

我真的建议现在将基类设置为接口:

public interface IProperty
{
    public String Name { get; }
}

public class Property<T> : IProperty
{
    public Property(String name, T value)
    {
        Name = name;
        Value = value;
    }

    public String Name { get; private set; }
    public T Value { get; private set; }

    public override String ToString()
    {
        return string.Format("{0}: {1}", Name, Value)
    }
}

这是示例用法:

var intProp = new Property<int>       ("age", 32);    
var strProp = new Property<string>    ("name", "Earl");    
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);    

为了使构造更加简单,您可以使用工厂方法:

public static Property<T> MakeProperty(string name, T value)
{
    return new Property<T>(name,value);
}

var intProp = MakeProperty("age", 32);    
var strProp = MakeProperty("name", "Earl");    
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);    


不一定推荐,而且有点过时:

你可以使用扩展方法让它变得更有趣:

public static Property<T> AsProp<T>(this T value, string name)
{
    return new Property<T>(name,value);
}

var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");

You can use a generic class:

public class AnyProperty<T> : Property
{
    private T value;
    // ... etc

I'd really recommend making the base class an Interface by now:

public interface IProperty
{
    public String Name { get; }
}

public class Property<T> : IProperty
{
    public Property(String name, T value)
    {
        Name = name;
        Value = value;
    }

    public String Name { get; private set; }
    public T Value { get; private set; }

    public override String ToString()
    {
        return string.Format("{0}: {1}", Name, Value)
    }
}

Here is sample usage:

var intProp = new Property<int>       ("age", 32);    
var strProp = new Property<string>    ("name", "Earl");    
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);    

To make the construction even simpler, you could have a factory method:

public static Property<T> MakeProperty(string name, T value)
{
    return new Property<T>(name,value);
}

var intProp = MakeProperty("age", 32);    
var strProp = MakeProperty("name", "Earl");    
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);    


Not necessarily recommended, and a bit OT:

You could make it even funkier with an extension method:

public static Property<T> AsProp<T>(this T value, string name)
{
    return new Property<T>(name,value);
}

var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");

胡渣熟男 2024-12-22 01:58:28

您必须简单地使用 object 类型。你想实现什么目标?这里的问题不在于类的结构,而在于接收 Property 对象集合的函数。甚至无法将某些内容转换为未知类型,因为您不知道它需要存储在什么类型的变量中。

因此基本上,您的 Property.Value 属性需要为 对象。在使用 Property 对象的方法中,您需要对它们执行一些操作,并且您所做的操作将决定它的结构。您正在打印值吗?有一个从抽象 PropertyValue 类继承的 *Value 类,并重写 ToString() 以返回适当的字符串表示形式。

You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.

So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.

清风挽心 2024-12-22 01:58:28

我对您的示例代码进行了一些更改并得到了这个结果...

   abstract public class Property
    {
        private readonly String _name;
        public Property(String propertyName)
        {
            _name = propertyName;
        }
        public String Name
        {
            get { return _name; }
        }
        abstract public override String ToString();
    }
    public class StringProperty : Property
    {
        private readonly dynamic _value; // different properties for different types 
        public StringProperty(String propertyName, dynamic value)
            : base(propertyName)
        {
            this._value = value;
        }
        public dynamic Value // different signature for different properties 
        {
            get { return _value; }
        }
        public override String ToString()
        {
            return base.Name + ": " + _value;
        }
    }
    static void Main(string[] args)
    {
        StringProperty sp = new StringProperty("A double", 3.444);
        StringProperty sp2 = new StringProperty("My int", 4343);
        StringProperty sp3 = new StringProperty("My directory", new  DirectoryInfo("Some directory"));
        StringProperty sp4 = new StringProperty("My null", null);
        Console.WriteLine(sp);
        Console.WriteLine(sp2);
        Console.WriteLine(sp3);
        Console.WriteLine(sp4);
    }
}

值以预期的方式正确打印到控制台。

I made a few changes to your sample code and got this result...

   abstract public class Property
    {
        private readonly String _name;
        public Property(String propertyName)
        {
            _name = propertyName;
        }
        public String Name
        {
            get { return _name; }
        }
        abstract public override String ToString();
    }
    public class StringProperty : Property
    {
        private readonly dynamic _value; // different properties for different types 
        public StringProperty(String propertyName, dynamic value)
            : base(propertyName)
        {
            this._value = value;
        }
        public dynamic Value // different signature for different properties 
        {
            get { return _value; }
        }
        public override String ToString()
        {
            return base.Name + ": " + _value;
        }
    }
    static void Main(string[] args)
    {
        StringProperty sp = new StringProperty("A double", 3.444);
        StringProperty sp2 = new StringProperty("My int", 4343);
        StringProperty sp3 = new StringProperty("My directory", new  DirectoryInfo("Some directory"));
        StringProperty sp4 = new StringProperty("My null", null);
        Console.WriteLine(sp);
        Console.WriteLine(sp2);
        Console.WriteLine(sp3);
        Console.WriteLine(sp4);
    }
}

Values are properly printed to the console in the expected way.

许仙没带伞 2024-12-22 01:58:28

这需要重新思考一下,但是您是否考虑过使用动态类型(在 .net4 中引入)

并不能真正解决您的问题,而是回避它。
您的属性基本上可以只是 a

Dictionary<String, dynamic>

,问题是它们直到运行时才会被评估,因此您得不到编译器对类型的支持。

所以既然你想要
int SomeValue = MyProperties[SomePropertyName] + 10;

所以如果
MyProperties[SomePropertyName] = 10; // 如果是 76.52 或 Fred,则一切都很好

,加法将在执行时抛出异常。

代码更加简单和干净,不需要额外的转换,并且所需的脚手架数量也很少,但是,您需要对广泛而虔诚地使用字典的代码进行单元测试。

It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)

Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a

Dictionary<String, dynamic>

, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.

so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;

So if
MyProperties[SomePropertyName] = 10; // all is good

if its 76.52 or Fred, the addition will throw an exception at the point it executes.

Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文