Getter和setter来自不同的界面

时间:2017-04-20 09:23:57

标签: c# interface

我真的需要这样的事情:

interface IReadableVar
{
    object Value { get; }
}

interface IWritableVar
{
    object Value { set; }
}

interface IReadableWritableVar : IReadableVar, IWritableVar
{
}

但是当我尝试使用IReadableWritableVar.Value时,除非我明确地转换为基接口,否则我会收到编译错误,如下所示:

static void Main()
{
    IReadableWritableVar var = null;
    var t = var.Value;  // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value'
    var.Value = null;   // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value'

    var v = ((IReadableVar)var).Value;  // compiles fine
    ((IWritableVar)var).Value = null;   // compiles fine
}

为什么我会得到这些错误,尽管编译器应该清楚一切?除了强制转换(应用程序中有数百个位置)之外,还有什么方法可以解决这个问题吗?

更新:有人认为这是Implementing 2 Interfaces with 'Same Name' Properties的欺骗,但这有点不同,因为在另一种情况下,接口中没有继承。无论如何,问题现在已经解决了 - 见接受的答案。

5 个答案:

答案 0 :(得分:15)

可能的解决方法是修改您的界面IReadableWritableVar,如下所示:

interface IReadableWritableVar : IReadableVar, IWritableVar
{
    new object Value { get; set; }
}

但请保持我的有效实施应该是:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    object IWritableVar.Value
    {
        set { throw new NotImplementedException(); }
    }

    object IReadableVar.Value
    {
        get { throw new NotImplementedException(); }
    }
}

更具体的例子:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value
    {
        get { return ((IReadableVar)this).Value; }
        set { ((IWritableVar)this).Value = value; }
    }

    object _val;

    object IWritableVar.Value { set { _val = value; } }

    object IReadableVar.Value => _val;
}

甚至更好:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value { get; set; }

    object IWritableVar.Value { set { Value = value; } }

    object IReadableVar.Value => Value;
}

答案 1 :(得分:7)

有趣的问题。我认为扩展方法在这种情况下会有所帮助。

public static class Extension
{
    public static object GetValue(this IReadableVar v)
    {
        return v.Value;
    }

    public static void SetValue(this IWritableVar v, object value)
    {
        v.Value = value;
    }
}

您需要更改代码才能使用它:

IReadableWritableVar variable = null;
var t = variable.GetValue();
variable.SetValue(null);

扩展方法为你做演员。

答案 2 :(得分:2)

嗯,有效的Getter和Setter只是两种方法。当我们使用IReadableWritableVar接口时,有两个方法具有从基接口继承的相同名称,并且编译器不知道它应该使用哪两个因此存在歧义。

当我们将其转换为其中一个接口时,其他成员已经消失,并且没有错误。

如果我们实现那些成员将没有错误,因为编译器将使用该实现:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value { get; set; }
}

var @var = new ReadableWritableVar();
var t = @var.Value;

如果要求你使用接口而不是类,你可以使用来自@Alessandro D'Andria的答案的显式接口成员实现。

答案 3 :(得分:0)

使用抽象类而不是接口将解决您的问题。

public abstract class ReadableWritableVar : IReadableVar, IWritableVar
{
    public object Value { get; set; }       
}

答案 4 :(得分:0)

一种可能的替代方法是使用显式(java风格)get和set方法而不是属性:

static void Main(string[] args)
{
    IReadableWritableVar aVar = null;

    var t = aVar.GetValue();
    aVar.SetValue(null);
}

然后用法变为:

// send image to Twitter first
$url = 'https://upload.twitter.com/1.1/media/upload.json';
$requestMethod = 'POST';

$image = 'full/path/to/image.jpg';

$postfields = array(
  'media_data' => base64_encode(file_get_contents($image))
);

$response = $twitter->buildOauth($url, $requestMethod)
  ->setPostfields($postfields)
  ->performRequest();

// get the media_id from the API return
$media_id = json_decode($response)->media_id;

// then send the Tweet along with the media ID
$url = 'https://api.twitter.com/1.1/statuses/update.json';
$requestMethod = 'POST';

$postfields = array(
  'status' => 'My amazing tweet'
  'media_ids' => $media_id,
);

$response = $twitter->buildOauth($url, $requestMethod)
  ->setPostfields($postfields)
  ->performRequest();