C# - 如何拥有一个引用实现一组接口的任何对象的类型?

发布于 2024-12-15 10:20:49 字数 675 浏览 3 评论 0原文

如何拥有引用实现一组接口的任何对象的类型引用?

例如,我可以有一个像这样的泛型类型:

Java:

public class Foo<T extends A & B> { }

C#

public class Foo<T> where T : A, B { }

这就是如何拥有一个类范围的泛型类型。但是,我只想有一个数据成员,它引用扩展给定接口集的任何对象。

示例:

public class Foo
{
    protected <? extends A, B> object;

    public void setObject(<? extends A, B> object)
    {
        this.object = object;
    }
}

如果可以使用这种类型语法,我如何在 Java 和 C# 中实现它?


我意识到我可以创建另一个扩展所有所需接口的接口。但是,我认为这不是最佳选择,因为它不必要地添加了另一种类型,其唯一目的是绕过语法。诚然,这是一个非常小的问题,但就优雅而言,它有点令人难堪。

How can I have a type reference that refers to any object that implements a set of interfaces?

For example, I can have a generic type like this:

Java:

public class Foo<T extends A & B> { }

C#

public class Foo<T> where T : A, B { }

That's how to have a class-wide generic type. However, I'd like to simply have a data member which references any object that extends a given set of interfaces.

Example:

public class Foo
{
    protected <? extends A, B> object;

    public void setObject(<? extends A, B> object)
    {
        this.object = object;
    }
}

If it's possible to have this sort of type syntax, how could I do it in both Java and C#?


I realize I can just create another interface that extends all desired interfaces. However, I don't see this as optimal, as it needlessly adds another type whose sole purpose is to get around syntax. Granted this is a very minor issue, but in terms of elegance it's a bit galling.

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

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

发布评论

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

评论(5

一个人的旅程 2024-12-22 10:20:49

由于两年的不活动,我的 Java 已经变得有点生疏了。

这是我的 C# 方法:(有关完整的工作示例,请参阅 https://ideone.com/N20xU

public class Foo
{
    private IInterface1 _object; // just pick one

    public void setObject<T>(T obj)
        where T : IInterface1, IComparable<T>, IEtcetera
    {
        // you now *know* that object supports all the interfaces
        // you don't need the compiler to remind you
        _object = obj; 
    }

    public void ExerciseObject()
    { 
        // completely safe due to the constraints on setObject<T>
        IEtcetera itf = (IEtcetera) _object;

        // ....
    }

My Java has become a bit rusty through 2years of inactivity.

Here's my C# approach: (see https://ideone.com/N20xU for full working sample)

public class Foo
{
    private IInterface1 _object; // just pick one

    public void setObject<T>(T obj)
        where T : IInterface1, IComparable<T>, IEtcetera
    {
        // you now *know* that object supports all the interfaces
        // you don't need the compiler to remind you
        _object = obj; 
    }

    public void ExerciseObject()
    { 
        // completely safe due to the constraints on setObject<T>
        IEtcetera itf = (IEtcetera) _object;

        // ....
    }
み零 2024-12-22 10:20:49

据我所知,您不能创建带有约束的变量,只能创建给定类型的变量。类型有限制。这意味着您必须定义一个具有所需约束的类型,然后使用该类型创建变量。

这对我来说似乎是合乎逻辑的,我不明白为什么你觉得必须为你需要的类型定义一个“令人烦恼”的事情。

As far as I know, You cannot create a variable with constraints on it, you can only create a variable of a given type. The type has the constraints. This means you have to define a type that has the constraints you desire, then create the variable with that type.

This seems logical to me, and I don't see why you find it "galling" to have to define a type for what you need.

睫毛溺水了 2024-12-22 10:20:49

在 C# 中,您可以使用元组以某种叠加< /a>:

public class Foo {
  private Tuple<IA, IB> junction;
  public void SetValue<T>(T value) where T : IA, IB {
    junction = Tuple.Create<IA, IB>(value, value);
  }
}

您还可以使用一个专门的类来强制两个值都引用同一对象的约束:

public class Junction {
  public IA A { get; private set; }
  public IB B { get; private set; }
  private Junction() { }
  public static Junction Create<T>(T value) where T: IA, IB {
    return new Junction {
      A = value,
      B = value
    };
  }
}

public class Foo {
  private Junction junction;
  public void SetValue<T>(T value) where T : IA, IB {
    junction = Junction.Create(value);
  }
}

在 Java 中,通配符可以稍微简化一些事情:

class Junction<E extends A & B> {
  private final E value;
  public Junction(E value) {
    this.value = value;
  }
  public E getValue() {
    return value;
  }
}

class Foo {
  private Junction<?> junction;
  public <E extends A & B> void setValue(E value) {
    junction = new Junction<E>(value);
  }
}

或者您可以使用别名 /em> 为相同的值(C#,但也适用于 Java):

public class Foo {
  private IA a;
  private IB b;
  public void SetValue<T>(T value) where T : IA, IB {
    a = value;
    b = value;
  }
}

In C#, you can use a tuple to store the value in a kind of superposition:

public class Foo {
  private Tuple<IA, IB> junction;
  public void SetValue<T>(T value) where T : IA, IB {
    junction = Tuple.Create<IA, IB>(value, value);
  }
}

You can also have a specialized class to enforce the constraint that both values reference the same object:

public class Junction {
  public IA A { get; private set; }
  public IB B { get; private set; }
  private Junction() { }
  public static Junction Create<T>(T value) where T: IA, IB {
    return new Junction {
      A = value,
      B = value
    };
  }
}

public class Foo {
  private Junction junction;
  public void SetValue<T>(T value) where T : IA, IB {
    junction = Junction.Create(value);
  }
}

In Java, a wildcard would simplify things a little:

class Junction<E extends A & B> {
  private final E value;
  public Junction(E value) {
    this.value = value;
  }
  public E getValue() {
    return value;
  }
}

class Foo {
  private Junction<?> junction;
  public <E extends A & B> void setValue(E value) {
    junction = new Junction<E>(value);
  }
}

Or you can have aliases to the same value (C#, but also applicable to Java):

public class Foo {
  private IA a;
  private IB b;
  public void SetValue<T>(T value) where T : IA, IB {
    a = value;
    b = value;
  }
}
┾廆蒐ゝ 2024-12-22 10:20:49

我认为简单地将约束声明为私有接口没有任何问题:

class Foo
{
    interface R : I1, I2 { }
    R _object;

    void setObject(R r) { _object = r; }
}

I don't see any problem with simply stating the constraints as a private interface:

class Foo
{
    interface R : I1, I2 { }
    R _object;

    void setObject(R r) { _object = r; }
}
东北女汉子 2024-12-22 10:20:49

这是我能想到的最好的解决方案(但仍然不是最佳解决方案)

public class Foo
{
    private TypeWrapper<IInterface1,IInterface2> _object;
    public void setObject<T>(T obj)
        where T : IInterface1, IInterface2
    {
        _object = new TypeWrapper<IInterface1, IInterface2>();
        _object.SetObject(obj);

        var val = _object.Get(h => h.c);
        Console.WriteLine(val);
        _object.Do(h => h.c = 25);
        val = _object.Get(h => h.c);
        Console.WriteLine(val);
        _object.Do(h => h.someF());
    }
}

public class TypeWrapper<TType, TTypeTwo>
{
    private Object m_Obj;
    public void SetObject<T>(T obj) where T : TType, TTypeTwo
    {
        m_Obj = obj;
    }

    public T Get<T>(Func<TType, T> action)
    {
        return (T)action((TType)m_Obj);
    }
    public T Get<T>(Func<TTypeTwo, T> action)
    {
        return (T)action((TTypeTwo)m_Obj);
    }

    public void Do(Action<TTypeTwo> action)
    {
        action((TTypeTwo)m_Obj);
    }

    public void Do(Action<TType> action)
    {
        action((TType)m_Obj);
    }
}

public class myClass : IInterface1, IInterface2 {
    public int t {get;set;}
    public int c {get;set;}
    public void someF() { Console.WriteLine("Fired"); }
    }
public interface IInterface1 {
    int t { get;set;} 
    void someF();
}
public interface IInterface2 { 
    int c { get;set; }
}

您将必须通过 Get 和 Do 方法来处理对象,但它将与智能感知一起工作,并在接口发生更改时抛出编译时错误。

Here's the best I could come up with (but still not an optimal solution)

public class Foo
{
    private TypeWrapper<IInterface1,IInterface2> _object;
    public void setObject<T>(T obj)
        where T : IInterface1, IInterface2
    {
        _object = new TypeWrapper<IInterface1, IInterface2>();
        _object.SetObject(obj);

        var val = _object.Get(h => h.c);
        Console.WriteLine(val);
        _object.Do(h => h.c = 25);
        val = _object.Get(h => h.c);
        Console.WriteLine(val);
        _object.Do(h => h.someF());
    }
}

public class TypeWrapper<TType, TTypeTwo>
{
    private Object m_Obj;
    public void SetObject<T>(T obj) where T : TType, TTypeTwo
    {
        m_Obj = obj;
    }

    public T Get<T>(Func<TType, T> action)
    {
        return (T)action((TType)m_Obj);
    }
    public T Get<T>(Func<TTypeTwo, T> action)
    {
        return (T)action((TTypeTwo)m_Obj);
    }

    public void Do(Action<TTypeTwo> action)
    {
        action((TTypeTwo)m_Obj);
    }

    public void Do(Action<TType> action)
    {
        action((TType)m_Obj);
    }
}

public class myClass : IInterface1, IInterface2 {
    public int t {get;set;}
    public int c {get;set;}
    public void someF() { Console.WriteLine("Fired"); }
    }
public interface IInterface1 {
    int t { get;set;} 
    void someF();
}
public interface IInterface2 { 
    int c { get;set; }
}

You're going to have to work on the object through the Get and Do methods, but it'll work with intellisense and throw compile time errors if the interfaces change.

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